Add system settings management features including controllers for managing system, social media, and marketplace settings. Implement request validation for each settings type and create corresponding UI components for user interaction. Update permissions in the Permission and Role enums to manage access to settings functionalities, and enhance the sidebar for navigation to the new settings sections.
This commit is contained in:
parent
9798150994
commit
67c27c2954
@ -77,6 +77,9 @@ enum Permission: string
|
|||||||
case PAYROLL_ADJUST = 'payroll.adjust';
|
case PAYROLL_ADJUST = 'payroll.adjust';
|
||||||
case PAYROLL_CLOSE = 'payroll.close';
|
case PAYROLL_CLOSE = 'payroll.close';
|
||||||
|
|
||||||
|
case SETTINGS_VIEW = 'settings.view';
|
||||||
|
case SETTINGS_UPDATE = 'settings.update';
|
||||||
|
|
||||||
public function label(): string
|
public function label(): string
|
||||||
{
|
{
|
||||||
return match ($this) {
|
return match ($this) {
|
||||||
@ -148,6 +151,9 @@ public function label(): string
|
|||||||
self::PAYROLL_PAY => 'Bayar Gaji',
|
self::PAYROLL_PAY => 'Bayar Gaji',
|
||||||
self::PAYROLL_ADJUST => 'Sesuaikan Gaji',
|
self::PAYROLL_ADJUST => 'Sesuaikan Gaji',
|
||||||
self::PAYROLL_CLOSE => 'Tutup Periode Gaji',
|
self::PAYROLL_CLOSE => 'Tutup Periode Gaji',
|
||||||
|
|
||||||
|
self::SETTINGS_VIEW => 'Lihat Pengaturan Aplikasi',
|
||||||
|
self::SETTINGS_UPDATE => 'Ubah Pengaturan Aplikasi',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,6 +185,7 @@ public function group(): string
|
|||||||
self::EMPLOYEE_ADVANCES_PAY => 'Kasbon',
|
self::EMPLOYEE_ADVANCES_PAY => 'Kasbon',
|
||||||
self::PAYROLL_VIEW, self::PAYROLL_PAY, self::PAYROLL_ADJUST,
|
self::PAYROLL_VIEW, self::PAYROLL_PAY, self::PAYROLL_ADJUST,
|
||||||
self::PAYROLL_CLOSE => 'Gaji',
|
self::PAYROLL_CLOSE => 'Gaji',
|
||||||
|
self::SETTINGS_VIEW, self::SETTINGS_UPDATE => 'Pengaturan Aplikasi',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -141,6 +141,8 @@ public function permissions(): array
|
|||||||
Permission::PAYROLL_PAY,
|
Permission::PAYROLL_PAY,
|
||||||
Permission::PAYROLL_ADJUST,
|
Permission::PAYROLL_ADJUST,
|
||||||
Permission::PAYROLL_CLOSE,
|
Permission::PAYROLL_CLOSE,
|
||||||
|
Permission::SETTINGS_VIEW,
|
||||||
|
Permission::SETTINGS_UPDATE,
|
||||||
],
|
],
|
||||||
self::ADMIN_BAHAN_BAKU => [
|
self::ADMIN_BAHAN_BAKU => [
|
||||||
Permission::DASHBOARD_VIEW,
|
Permission::DASHBOARD_VIEW,
|
||||||
|
|||||||
59
app/Http/Controllers/Admin/System/SettingController.php
Normal file
59
app/Http/Controllers/Admin/System/SettingController.php
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Admin\System;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Admin\System\Setting\MarketplaceRequest;
|
||||||
|
use App\Http\Requests\Admin\System\Setting\SocialMediaRequest;
|
||||||
|
use App\Http\Requests\Admin\System\Setting\SystemRequest;
|
||||||
|
use App\Services\System\Setting\MarketplaceService;
|
||||||
|
use App\Services\System\Setting\SocialMediaService;
|
||||||
|
use App\Services\System\Setting\SystemService;
|
||||||
|
use Illuminate\Http\RedirectResponse;
|
||||||
|
use Inertia\Inertia;
|
||||||
|
use Inertia\Response;
|
||||||
|
|
||||||
|
class SettingController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly SystemService $systemService,
|
||||||
|
private readonly SocialMediaService $socialMediaService,
|
||||||
|
private readonly MarketplaceService $marketplaceService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function index(): Response
|
||||||
|
{
|
||||||
|
return Inertia::render('admin/system/setting/Index', [
|
||||||
|
'system' => $this->systemService->systemData(),
|
||||||
|
'socialMedia' => $this->socialMediaService->socialMediaData(),
|
||||||
|
'marketplace' => $this->marketplaceService->marketplaceData(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateSystem(SystemRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->systemService->updateSystem($request->validated());
|
||||||
|
|
||||||
|
Inertia::flash('success', 'Pengaturan sistem berhasil disimpan.');
|
||||||
|
|
||||||
|
return redirect()->route('admin.system.setting.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateSocialMedia(SocialMediaRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->socialMediaService->updateSocialMedia($request->validated());
|
||||||
|
|
||||||
|
Inertia::flash('success', 'Pengaturan media sosial berhasil disimpan.');
|
||||||
|
|
||||||
|
return redirect()->route('admin.system.setting.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateMarketplace(MarketplaceRequest $request): RedirectResponse
|
||||||
|
{
|
||||||
|
$this->marketplaceService->updateMarketplace($request->validated());
|
||||||
|
|
||||||
|
Inertia::flash('success', 'Pengaturan marketplace berhasil disimpan.');
|
||||||
|
|
||||||
|
return redirect()->route('admin.system.setting.index');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Admin\System\Setting;
|
||||||
|
|
||||||
|
use App\Enums\Permission;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class MarketplaceRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'tiktok_shop_enabled' => ['required', 'boolean'],
|
||||||
|
'tiktok_shop_admin_fee' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'tiktok_shop_transaction_fee' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'tiktok_shop_payment_fee' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'tiktok_shop_affiliate_commission' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'tiktok_shop_shipping_subsidy' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'tiktok_shop_vat_rate' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'tiktok_shop_url' => ['nullable', 'url', 'max:500'],
|
||||||
|
'tiktok_shop_id' => ['nullable', 'string', 'max:100'],
|
||||||
|
|
||||||
|
'shopee_enabled' => ['required', 'boolean'],
|
||||||
|
'shopee_commission_fee' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'shopee_transaction_fee' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'shopee_service_fee' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'shopee_payment_fee' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'shopee_affiliate_commission' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'shopee_shipping_subsidy' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'shopee_voucher_fee' => ['required', 'numeric', 'min:0', 'max:100'],
|
||||||
|
'shopee_shop_url' => ['nullable', 'url', 'max:500'],
|
||||||
|
'shopee_shop_id' => ['nullable', 'string', 'max:100'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Admin\System\Setting;
|
||||||
|
|
||||||
|
use App\Enums\Permission;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class SocialMediaRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'instagram_url' => ['nullable', 'url', 'max:100'],
|
||||||
|
'facebook_url' => ['nullable', 'url', 'max:100'],
|
||||||
|
'tiktok_url' => ['nullable', 'url', 'max:100'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
26
app/Http/Requests/Admin/System/Setting/SystemRequest.php
Normal file
26
app/Http/Requests/Admin/System/Setting/SystemRequest.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Admin\System\Setting;
|
||||||
|
|
||||||
|
use App\Enums\Permission;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class SystemRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'app_name' => ['required', 'string', 'max:100'],
|
||||||
|
'about_app' => ['nullable', 'string'],
|
||||||
|
'email' => ['nullable', 'email', 'max:100'],
|
||||||
|
'phone' => ['nullable', 'string', 'max:20'],
|
||||||
|
'logo' => ['nullable', 'image', 'max:2048'],
|
||||||
|
'login_cover' => ['nullable', 'image', 'max:5120'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
63
app/Services/System/Setting/MarketplaceService.php
Normal file
63
app/Services/System/Setting/MarketplaceService.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\System\Setting;
|
||||||
|
|
||||||
|
use App\Settings\MarketplaceSettings;
|
||||||
|
|
||||||
|
class MarketplaceService
|
||||||
|
{
|
||||||
|
public function marketplaceData(): array
|
||||||
|
{
|
||||||
|
$settings = app(MarketplaceSettings::class);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'tiktok_shop_enabled' => $settings->tiktok_shop_enabled,
|
||||||
|
'tiktok_shop_admin_fee' => $settings->tiktok_shop_admin_fee,
|
||||||
|
'tiktok_shop_transaction_fee' => $settings->tiktok_shop_transaction_fee,
|
||||||
|
'tiktok_shop_payment_fee' => $settings->tiktok_shop_payment_fee,
|
||||||
|
'tiktok_shop_affiliate_commission' => $settings->tiktok_shop_affiliate_commission,
|
||||||
|
'tiktok_shop_shipping_subsidy' => $settings->tiktok_shop_shipping_subsidy,
|
||||||
|
'tiktok_shop_vat_rate' => $settings->tiktok_shop_vat_rate,
|
||||||
|
'tiktok_shop_url' => $settings->tiktok_shop_url,
|
||||||
|
'tiktok_shop_id' => $settings->tiktok_shop_id,
|
||||||
|
'shopee_enabled' => $settings->shopee_enabled,
|
||||||
|
'shopee_commission_fee' => $settings->shopee_commission_fee,
|
||||||
|
'shopee_transaction_fee' => $settings->shopee_transaction_fee,
|
||||||
|
'shopee_service_fee' => $settings->shopee_service_fee,
|
||||||
|
'shopee_payment_fee' => $settings->shopee_payment_fee,
|
||||||
|
'shopee_affiliate_commission' => $settings->shopee_affiliate_commission,
|
||||||
|
'shopee_shipping_subsidy' => $settings->shopee_shipping_subsidy,
|
||||||
|
'shopee_voucher_fee' => $settings->shopee_voucher_fee,
|
||||||
|
'shopee_shop_url' => $settings->shopee_shop_url,
|
||||||
|
'shopee_shop_id' => $settings->shopee_shop_id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateMarketplace(array $validated): void
|
||||||
|
{
|
||||||
|
$settings = app(MarketplaceSettings::class);
|
||||||
|
|
||||||
|
$settings->tiktok_shop_enabled = $validated['tiktok_shop_enabled'];
|
||||||
|
$settings->tiktok_shop_admin_fee = $validated['tiktok_shop_admin_fee'];
|
||||||
|
$settings->tiktok_shop_transaction_fee = $validated['tiktok_shop_transaction_fee'];
|
||||||
|
$settings->tiktok_shop_payment_fee = $validated['tiktok_shop_payment_fee'];
|
||||||
|
$settings->tiktok_shop_affiliate_commission = $validated['tiktok_shop_affiliate_commission'];
|
||||||
|
$settings->tiktok_shop_shipping_subsidy = $validated['tiktok_shop_shipping_subsidy'];
|
||||||
|
$settings->tiktok_shop_vat_rate = $validated['tiktok_shop_vat_rate'];
|
||||||
|
$settings->tiktok_shop_url = $validated['tiktok_shop_url'] ?? null;
|
||||||
|
$settings->tiktok_shop_id = $validated['tiktok_shop_id'] ?? null;
|
||||||
|
|
||||||
|
$settings->shopee_enabled = $validated['shopee_enabled'];
|
||||||
|
$settings->shopee_commission_fee = $validated['shopee_commission_fee'];
|
||||||
|
$settings->shopee_transaction_fee = $validated['shopee_transaction_fee'];
|
||||||
|
$settings->shopee_service_fee = $validated['shopee_service_fee'];
|
||||||
|
$settings->shopee_payment_fee = $validated['shopee_payment_fee'];
|
||||||
|
$settings->shopee_affiliate_commission = $validated['shopee_affiliate_commission'];
|
||||||
|
$settings->shopee_shipping_subsidy = $validated['shopee_shipping_subsidy'];
|
||||||
|
$settings->shopee_voucher_fee = $validated['shopee_voucher_fee'];
|
||||||
|
$settings->shopee_shop_url = $validated['shopee_shop_url'] ?? null;
|
||||||
|
$settings->shopee_shop_id = $validated['shopee_shop_id'] ?? null;
|
||||||
|
|
||||||
|
$settings->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
30
app/Services/System/Setting/SocialMediaService.php
Normal file
30
app/Services/System/Setting/SocialMediaService.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\System\Setting;
|
||||||
|
|
||||||
|
use App\Settings\SocialMediaSettings;
|
||||||
|
|
||||||
|
class SocialMediaService
|
||||||
|
{
|
||||||
|
public function socialMediaData(): array
|
||||||
|
{
|
||||||
|
$settings = app(SocialMediaSettings::class);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'instagram_url' => $settings->instagram_url,
|
||||||
|
'facebook_url' => $settings->facebook_url,
|
||||||
|
'tiktok_url' => $settings->tiktok_url,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateSocialMedia(array $validated): void
|
||||||
|
{
|
||||||
|
$settings = app(SocialMediaSettings::class);
|
||||||
|
|
||||||
|
$settings->instagram_url = $validated['instagram_url'] ?? null;
|
||||||
|
$settings->facebook_url = $validated['facebook_url'] ?? null;
|
||||||
|
$settings->tiktok_url = $validated['tiktok_url'] ?? null;
|
||||||
|
|
||||||
|
$settings->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
48
app/Services/System/Setting/SystemService.php
Normal file
48
app/Services/System/Setting/SystemService.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\System\Setting;
|
||||||
|
|
||||||
|
use App\Settings\SystemSettings;
|
||||||
|
use Illuminate\Http\UploadedFile;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class SystemService
|
||||||
|
{
|
||||||
|
public function systemData(): array
|
||||||
|
{
|
||||||
|
$settings = app(SystemSettings::class);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'app_name' => $settings->app_name,
|
||||||
|
'about_app' => $settings->about_app,
|
||||||
|
'email' => $settings->email,
|
||||||
|
'phone' => $settings->phone,
|
||||||
|
'logo' => $settings->logo,
|
||||||
|
'logo_url' => $settings->logo ? Storage::disk('public')->url($settings->logo) : null,
|
||||||
|
'login_cover' => $settings->login_cover,
|
||||||
|
'login_cover_url' => $settings->login_cover ? Storage::disk('public')->url($settings->login_cover) : null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateSystem(array $validated): void
|
||||||
|
{
|
||||||
|
$settings = app(SystemSettings::class);
|
||||||
|
|
||||||
|
$settings->app_name = $validated['app_name'];
|
||||||
|
$settings->about_app = $validated['about_app'] ?? null;
|
||||||
|
$settings->email = $validated['email'] ?? null;
|
||||||
|
$settings->phone = $validated['phone'] ?? null;
|
||||||
|
|
||||||
|
if (isset($validated['logo']) && $validated['logo'] instanceof UploadedFile) {
|
||||||
|
Storage::disk('public')->delete($settings->logo);
|
||||||
|
$settings->logo = $validated['logo']->store('settings/system', 'public');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($validated['login_cover']) && $validated['login_cover'] instanceof UploadedFile) {
|
||||||
|
Storage::disk('public')->delete($settings->login_cover);
|
||||||
|
$settings->login_cover = $validated['login_cover']->store('settings/system', 'public');
|
||||||
|
}
|
||||||
|
|
||||||
|
$settings->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
51
app/Settings/MarketplaceSettings.php
Normal file
51
app/Settings/MarketplaceSettings.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Settings;
|
||||||
|
|
||||||
|
use Spatie\LaravelSettings\Settings;
|
||||||
|
|
||||||
|
class MarketplaceSettings extends Settings
|
||||||
|
{
|
||||||
|
public bool $tiktok_shop_enabled;
|
||||||
|
|
||||||
|
public float $tiktok_shop_admin_fee;
|
||||||
|
|
||||||
|
public float $tiktok_shop_transaction_fee;
|
||||||
|
|
||||||
|
public float $tiktok_shop_payment_fee;
|
||||||
|
|
||||||
|
public float $tiktok_shop_affiliate_commission;
|
||||||
|
|
||||||
|
public float $tiktok_shop_shipping_subsidy;
|
||||||
|
|
||||||
|
public float $tiktok_shop_vat_rate;
|
||||||
|
|
||||||
|
public ?string $tiktok_shop_url;
|
||||||
|
|
||||||
|
public ?string $tiktok_shop_id;
|
||||||
|
|
||||||
|
public bool $shopee_enabled;
|
||||||
|
|
||||||
|
public float $shopee_commission_fee;
|
||||||
|
|
||||||
|
public float $shopee_transaction_fee;
|
||||||
|
|
||||||
|
public float $shopee_service_fee;
|
||||||
|
|
||||||
|
public float $shopee_payment_fee;
|
||||||
|
|
||||||
|
public float $shopee_affiliate_commission;
|
||||||
|
|
||||||
|
public float $shopee_shipping_subsidy;
|
||||||
|
|
||||||
|
public float $shopee_voucher_fee;
|
||||||
|
|
||||||
|
public ?string $shopee_shop_url;
|
||||||
|
|
||||||
|
public ?string $shopee_shop_id;
|
||||||
|
|
||||||
|
public static function group(): string
|
||||||
|
{
|
||||||
|
return 'marketplace';
|
||||||
|
}
|
||||||
|
}
|
||||||
19
app/Settings/SocialMediaSettings.php
Normal file
19
app/Settings/SocialMediaSettings.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Settings;
|
||||||
|
|
||||||
|
use Spatie\LaravelSettings\Settings;
|
||||||
|
|
||||||
|
class SocialMediaSettings extends Settings
|
||||||
|
{
|
||||||
|
public ?string $instagram_url;
|
||||||
|
|
||||||
|
public ?string $facebook_url;
|
||||||
|
|
||||||
|
public ?string $tiktok_url;
|
||||||
|
|
||||||
|
public static function group(): string
|
||||||
|
{
|
||||||
|
return 'social_media';
|
||||||
|
}
|
||||||
|
}
|
||||||
25
app/Settings/SystemSettings.php
Normal file
25
app/Settings/SystemSettings.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Settings;
|
||||||
|
|
||||||
|
use Spatie\LaravelSettings\Settings;
|
||||||
|
|
||||||
|
class SystemSettings extends Settings
|
||||||
|
{
|
||||||
|
public string $app_name;
|
||||||
|
|
||||||
|
public ?string $about_app;
|
||||||
|
|
||||||
|
public ?string $email;
|
||||||
|
|
||||||
|
public ?string $phone;
|
||||||
|
|
||||||
|
public ?string $logo;
|
||||||
|
|
||||||
|
public ?string $login_cover;
|
||||||
|
|
||||||
|
public static function group(): string
|
||||||
|
{
|
||||||
|
return 'system';
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,6 +15,7 @@
|
|||||||
"laravel/tinker": "^3.0",
|
"laravel/tinker": "^3.0",
|
||||||
"laravel/wayfinder": "^0.1.14",
|
"laravel/wayfinder": "^0.1.14",
|
||||||
"spatie/laravel-permission": "^8.0",
|
"spatie/laravel-permission": "^8.0",
|
||||||
|
"spatie/laravel-settings": "^3.9",
|
||||||
"spatie/laravel-sluggable": "^4.0"
|
"spatie/laravel-sluggable": "^4.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
|||||||
466
composer.lock
generated
466
composer.lock
generated
@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "dd4192a3bb321ccbee15386b55196fc5",
|
"content-hash": "25e9e3d1a32e479b704c046ede69c405",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
@ -210,6 +210,54 @@
|
|||||||
},
|
},
|
||||||
"time": "2024-07-08T12:26:09+00:00"
|
"time": "2024-07-08T12:26:09+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/deprecations",
|
||||||
|
"version": "1.1.6",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/deprecations.git",
|
||||||
|
"reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca",
|
||||||
|
"reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"phpunit/phpunit": "<=7.5 || >=14"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/coding-standard": "^9 || ^12 || ^14",
|
||||||
|
"phpstan/phpstan": "1.4.10 || 2.1.30",
|
||||||
|
"phpstan/phpstan-phpunit": "^1.0 || ^2",
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0",
|
||||||
|
"psr/log": "^1 || ^2 || ^3"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\Deprecations\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
|
||||||
|
"homepage": "https://www.doctrine-project.org/",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/doctrine/deprecations/issues",
|
||||||
|
"source": "https://github.com/doctrine/deprecations/tree/1.1.6"
|
||||||
|
},
|
||||||
|
"time": "2026-02-07T07:09:04+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/inflector",
|
"name": "doctrine/inflector",
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
@ -2677,6 +2725,117 @@
|
|||||||
],
|
],
|
||||||
"time": "2026-02-16T23:10:27+00:00"
|
"time": "2026-02-16T23:10:27+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "phpdocumentor/reflection-common",
|
||||||
|
"version": "2.2.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
|
||||||
|
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
|
||||||
|
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2 || ^8.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-2.x": "2.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"phpDocumentor\\Reflection\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jaap van Otterdijk",
|
||||||
|
"email": "opensource@ijaap.nl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Common reflection classes used by phpdocumentor to reflect the code structure",
|
||||||
|
"homepage": "http://www.phpdoc.org",
|
||||||
|
"keywords": [
|
||||||
|
"FQSEN",
|
||||||
|
"phpDocumentor",
|
||||||
|
"phpdoc",
|
||||||
|
"reflection",
|
||||||
|
"static analysis"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
|
||||||
|
"source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
|
||||||
|
},
|
||||||
|
"time": "2020-06-27T09:03:43+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "phpdocumentor/type-resolver",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/phpDocumentor/TypeResolver.git",
|
||||||
|
"reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/327a05bbee54120d4786a0dc67aad30226ad4cf9",
|
||||||
|
"reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"doctrine/deprecations": "^1.0",
|
||||||
|
"php": "^7.4 || ^8.0",
|
||||||
|
"phpdocumentor/reflection-common": "^2.0",
|
||||||
|
"phpstan/phpdoc-parser": "^2.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-tokenizer": "*",
|
||||||
|
"phpbench/phpbench": "^1.2",
|
||||||
|
"phpstan/extension-installer": "^1.4",
|
||||||
|
"phpstan/phpstan": "^2.1",
|
||||||
|
"phpstan/phpstan-phpunit": "^2.0",
|
||||||
|
"phpunit/phpunit": "^9.5",
|
||||||
|
"psalm/phar": "^4"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-1.x": "1.x-dev",
|
||||||
|
"dev-2.x": "2.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"phpDocumentor\\Reflection\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Mike van Riel",
|
||||||
|
"email": "me@mikevanriel.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
|
||||||
|
"source": "https://github.com/phpDocumentor/TypeResolver/tree/2.0.0"
|
||||||
|
},
|
||||||
|
"time": "2026-01-06T21:53:42+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "phpoption/phpoption",
|
"name": "phpoption/phpoption",
|
||||||
"version": "1.9.5",
|
"version": "1.9.5",
|
||||||
@ -3636,6 +3795,91 @@
|
|||||||
],
|
],
|
||||||
"time": "2026-05-30T19:30:22+00:00"
|
"time": "2026-05-30T19:30:22+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "spatie/laravel-settings",
|
||||||
|
"version": "3.9.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/spatie/laravel-settings.git",
|
||||||
|
"reference": "6c1351cf57c4ae96cd2313ae395c6d367dfeee01"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/spatie/laravel-settings/zipball/6c1351cf57c4ae96cd2313ae395c6d367dfeee01",
|
||||||
|
"reference": "6c1351cf57c4ae96cd2313ae395c6d367dfeee01",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-json": "*",
|
||||||
|
"illuminate/database": "^11.0|^12.0|^13.0",
|
||||||
|
"php": "^8.2",
|
||||||
|
"phpdocumentor/type-resolver": "^1.5|^2.0",
|
||||||
|
"spatie/temporary-directory": "^1.3|^2.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-redis": "*",
|
||||||
|
"mockery/mockery": "^1.4",
|
||||||
|
"orchestra/testbench": "^9.0|^10.0|^11.0",
|
||||||
|
"pestphp/pest": "^2.0|^3.0|^4.0",
|
||||||
|
"pestphp/pest-plugin-laravel": "^2.0|^3.0|^4.0",
|
||||||
|
"phpstan/extension-installer": "^1.1",
|
||||||
|
"phpstan/phpstan-deprecation-rules": "^1.0",
|
||||||
|
"phpstan/phpstan-phpunit": "^1.0",
|
||||||
|
"spatie/laravel-data": "^2.0.0|^4.0.0",
|
||||||
|
"spatie/pest-plugin-snapshots": "^2.0",
|
||||||
|
"spatie/phpunit-snapshot-assertions": "^4.2|^5.0",
|
||||||
|
"spatie/ray": "^1.36"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"spatie/data-transfer-object": "Allows for DTO casting to settings. (deprecated)"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"providers": [
|
||||||
|
"Spatie\\LaravelSettings\\LaravelSettingsServiceProvider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Spatie\\LaravelSettings\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Ruben Van Assche",
|
||||||
|
"email": "ruben@spatie.be",
|
||||||
|
"homepage": "https://spatie.be",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Store your application settings",
|
||||||
|
"homepage": "https://github.com/spatie/laravel-settings",
|
||||||
|
"keywords": [
|
||||||
|
"laravel-settings",
|
||||||
|
"spatie"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/spatie/laravel-settings/issues",
|
||||||
|
"source": "https://github.com/spatie/laravel-settings/tree/3.9.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://spatie.be/open-source/support-us",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/spatie",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-05-26T13:18:06+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "spatie/laravel-sluggable",
|
"name": "spatie/laravel-sluggable",
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
@ -3714,6 +3958,67 @@
|
|||||||
],
|
],
|
||||||
"time": "2026-04-30T17:28:09+00:00"
|
"time": "2026-04-30T17:28:09+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "spatie/temporary-directory",
|
||||||
|
"version": "2.3.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/spatie/temporary-directory.git",
|
||||||
|
"reference": "662e481d6ec07ef29fd05010433428851a42cd07"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/spatie/temporary-directory/zipball/662e481d6ec07ef29fd05010433428851a42cd07",
|
||||||
|
"reference": "662e481d6ec07ef29fd05010433428851a42cd07",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Spatie\\TemporaryDirectory\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Alex Vanderbist",
|
||||||
|
"email": "alex@spatie.be",
|
||||||
|
"homepage": "https://spatie.be",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Easily create, use and destroy temporary directories",
|
||||||
|
"homepage": "https://github.com/spatie/temporary-directory",
|
||||||
|
"keywords": [
|
||||||
|
"php",
|
||||||
|
"spatie",
|
||||||
|
"temporary-directory"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/spatie/temporary-directory/issues",
|
||||||
|
"source": "https://github.com/spatie/temporary-directory/tree/2.3.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://spatie.be/open-source/support-us",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/spatie",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2026-01-12T07:42:22+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/clock",
|
"name": "symfony/clock",
|
||||||
"version": "v8.1.0",
|
"version": "v8.1.0",
|
||||||
@ -6646,54 +6951,6 @@
|
|||||||
],
|
],
|
||||||
"time": "2024-05-06T16:37:16+00:00"
|
"time": "2024-05-06T16:37:16+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "doctrine/deprecations",
|
|
||||||
"version": "1.1.6",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/doctrine/deprecations.git",
|
|
||||||
"reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca",
|
|
||||||
"reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": "^7.1 || ^8.0"
|
|
||||||
},
|
|
||||||
"conflict": {
|
|
||||||
"phpunit/phpunit": "<=7.5 || >=14"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"doctrine/coding-standard": "^9 || ^12 || ^14",
|
|
||||||
"phpstan/phpstan": "1.4.10 || 2.1.30",
|
|
||||||
"phpstan/phpstan-phpunit": "^1.0 || ^2",
|
|
||||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0",
|
|
||||||
"psr/log": "^1 || ^2 || ^3"
|
|
||||||
},
|
|
||||||
"suggest": {
|
|
||||||
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Doctrine\\Deprecations\\": "src"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
|
|
||||||
"homepage": "https://www.doctrine-project.org/",
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/doctrine/deprecations/issues",
|
|
||||||
"source": "https://github.com/doctrine/deprecations/tree/1.1.6"
|
|
||||||
},
|
|
||||||
"time": "2026-02-07T07:09:04+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "fakerphp/faker",
|
"name": "fakerphp/faker",
|
||||||
"version": "v1.24.1",
|
"version": "v1.24.1",
|
||||||
@ -8180,59 +8437,6 @@
|
|||||||
},
|
},
|
||||||
"time": "2022-02-21T01:04:05+00:00"
|
"time": "2022-02-21T01:04:05+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "phpdocumentor/reflection-common",
|
|
||||||
"version": "2.2.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
|
|
||||||
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b",
|
|
||||||
"reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": "^7.2 || ^8.0"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-2.x": "2.x-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"phpDocumentor\\Reflection\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Jaap van Otterdijk",
|
|
||||||
"email": "opensource@ijaap.nl"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Common reflection classes used by phpdocumentor to reflect the code structure",
|
|
||||||
"homepage": "http://www.phpdoc.org",
|
|
||||||
"keywords": [
|
|
||||||
"FQSEN",
|
|
||||||
"phpDocumentor",
|
|
||||||
"phpdoc",
|
|
||||||
"reflection",
|
|
||||||
"static analysis"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
|
|
||||||
"source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x"
|
|
||||||
},
|
|
||||||
"time": "2020-06-27T09:03:43+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "phpdocumentor/reflection-docblock",
|
"name": "phpdocumentor/reflection-docblock",
|
||||||
"version": "6.0.3",
|
"version": "6.0.3",
|
||||||
@ -8298,64 +8502,6 @@
|
|||||||
},
|
},
|
||||||
"time": "2026-03-18T20:49:53+00:00"
|
"time": "2026-03-18T20:49:53+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "phpdocumentor/type-resolver",
|
|
||||||
"version": "2.0.0",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/phpDocumentor/TypeResolver.git",
|
|
||||||
"reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/327a05bbee54120d4786a0dc67aad30226ad4cf9",
|
|
||||||
"reference": "327a05bbee54120d4786a0dc67aad30226ad4cf9",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"doctrine/deprecations": "^1.0",
|
|
||||||
"php": "^7.4 || ^8.0",
|
|
||||||
"phpdocumentor/reflection-common": "^2.0",
|
|
||||||
"phpstan/phpdoc-parser": "^2.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"ext-tokenizer": "*",
|
|
||||||
"phpbench/phpbench": "^1.2",
|
|
||||||
"phpstan/extension-installer": "^1.4",
|
|
||||||
"phpstan/phpstan": "^2.1",
|
|
||||||
"phpstan/phpstan-phpunit": "^2.0",
|
|
||||||
"phpunit/phpunit": "^9.5",
|
|
||||||
"psalm/phar": "^4"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-1.x": "1.x-dev",
|
|
||||||
"dev-2.x": "2.x-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"phpDocumentor\\Reflection\\": "src"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Mike van Riel",
|
|
||||||
"email": "me@mikevanriel.com"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
|
|
||||||
"source": "https://github.com/phpDocumentor/TypeResolver/tree/2.0.0"
|
|
||||||
},
|
|
||||||
"time": "2026-01-06T21:53:42+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "phpunit/php-code-coverage",
|
"name": "phpunit/php-code-coverage",
|
||||||
"version": "12.5.7",
|
"version": "12.5.7",
|
||||||
|
|||||||
107
config/settings.php
Normal file
107
config/settings.php
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Spatie\LaravelData\Data;
|
||||||
|
use Spatie\LaravelSettings\SettingsCasts\DataCast;
|
||||||
|
use Spatie\LaravelSettings\SettingsCasts\DateTimeInterfaceCast;
|
||||||
|
use Spatie\LaravelSettings\SettingsCasts\DateTimeZoneCast;
|
||||||
|
use Spatie\LaravelSettings\SettingsRepositories\DatabaseSettingsRepository;
|
||||||
|
use Spatie\LaravelSettings\SettingsRepositories\RedisSettingsRepository;
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each settings class used in your application must be registered, you can
|
||||||
|
* put them (manually) here.
|
||||||
|
*/
|
||||||
|
'settings' => [
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The path where the settings classes will be created.
|
||||||
|
*/
|
||||||
|
'setting_class_path' => app_path('Settings'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In these directories settings migrations will be stored and ran when migrating. A settings
|
||||||
|
* migration created via the make:settings-migration command will be stored in the first path or
|
||||||
|
* a custom defined path when running the command.
|
||||||
|
*/
|
||||||
|
'migrations_paths' => [
|
||||||
|
database_path('settings'),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When no repository was set for a settings class the following repository
|
||||||
|
* will be used for loading and saving settings.
|
||||||
|
*/
|
||||||
|
'default_repository' => 'database',
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Settings will be stored and loaded from these repositories.
|
||||||
|
*/
|
||||||
|
'repositories' => [
|
||||||
|
'database' => [
|
||||||
|
'type' => DatabaseSettingsRepository::class,
|
||||||
|
'model' => null,
|
||||||
|
'table' => null,
|
||||||
|
'connection' => null,
|
||||||
|
],
|
||||||
|
'redis' => [
|
||||||
|
'type' => RedisSettingsRepository::class,
|
||||||
|
'connection' => null,
|
||||||
|
'prefix' => null,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The encoder and decoder will determine how settings are stored and
|
||||||
|
* retrieved in the database. By default, `json_encode` and `json_decode`
|
||||||
|
* are used.
|
||||||
|
*/
|
||||||
|
'encoder' => null,
|
||||||
|
'decoder' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The contents of settings classes can be cached through your application,
|
||||||
|
* settings will be stored within a provided Laravel store and can have an
|
||||||
|
* additional prefix.
|
||||||
|
*/
|
||||||
|
'cache' => [
|
||||||
|
'enabled' => (bool) env('SETTINGS_CACHE_ENABLED', false),
|
||||||
|
'store' => null,
|
||||||
|
'prefix' => null,
|
||||||
|
'ttl' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When enabled, uses Laravel's memoized cache driver (requires Laravel 12.9+)
|
||||||
|
* to keep resolved values in memory during a single request.
|
||||||
|
*/
|
||||||
|
'memo' => env('SETTINGS_CACHE_MEMO', false),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These global casts will be automatically used whenever a property within
|
||||||
|
* your settings class isn't a default PHP type.
|
||||||
|
*/
|
||||||
|
'global_casts' => [
|
||||||
|
DateTimeInterface::class => DateTimeInterfaceCast::class,
|
||||||
|
DateTimeZone::class => DateTimeZoneCast::class,
|
||||||
|
// Spatie\DataTransferObject\DataTransferObject::class => Spatie\LaravelSettings\SettingsCasts\DtoCast::class,
|
||||||
|
Data::class => DataCast::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The package will look for settings in these paths and automatically
|
||||||
|
* register them.
|
||||||
|
*/
|
||||||
|
'auto_discover_settings' => [
|
||||||
|
app_path('Settings'),
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Automatically discovered settings classes can be cached, so they don't
|
||||||
|
* need to be searched each time the application boots up.
|
||||||
|
*/
|
||||||
|
'discovered_settings_cache_path' => base_path('bootstrap/cache'),
|
||||||
|
];
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create(config('settings.repositories.database.table') ?? 'settings', function (Blueprint $table): void {
|
||||||
|
$table->id();
|
||||||
|
|
||||||
|
$table->string('group');
|
||||||
|
$table->string('name');
|
||||||
|
$table->boolean('locked')->default(false);
|
||||||
|
$table->json('payload');
|
||||||
|
|
||||||
|
$table->timestamp('created_at')->useCurrent();
|
||||||
|
$table->timestamp('updated_at')->useCurrent()->useCurrentOnUpdate();
|
||||||
|
|
||||||
|
$table->unique(['group', 'name']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
48
database/settings/2026_06_11_085959_create_app_settings.php
Normal file
48
database/settings/2026_06_11_085959_create_app_settings.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Spatie\LaravelSettings\Migrations\SettingsBlueprint;
|
||||||
|
use Spatie\LaravelSettings\Migrations\SettingsMigration;
|
||||||
|
|
||||||
|
return new class extends SettingsMigration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
$this->migrator->inGroup('system', function (SettingsBlueprint $blueprint): void {
|
||||||
|
$blueprint->add('app_name', config('app.name', 'DST Collection'));
|
||||||
|
$blueprint->add('about_app', null);
|
||||||
|
$blueprint->add('email', null);
|
||||||
|
$blueprint->add('phone', null);
|
||||||
|
$blueprint->add('logo', null);
|
||||||
|
$blueprint->add('login_cover', null);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->migrator->inGroup('social_media', function (SettingsBlueprint $blueprint): void {
|
||||||
|
$blueprint->add('instagram_url', null);
|
||||||
|
$blueprint->add('facebook_url', null);
|
||||||
|
$blueprint->add('tiktok_url', null);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->migrator->inGroup('marketplace', function (SettingsBlueprint $blueprint): void {
|
||||||
|
$blueprint->add('tiktok_shop_enabled', true);
|
||||||
|
$blueprint->add('tiktok_shop_admin_fee', 5.0);
|
||||||
|
$blueprint->add('tiktok_shop_transaction_fee', 1.0);
|
||||||
|
$blueprint->add('tiktok_shop_payment_fee', 0.7);
|
||||||
|
$blueprint->add('tiktok_shop_affiliate_commission', 0.0);
|
||||||
|
$blueprint->add('tiktok_shop_shipping_subsidy', 0.0);
|
||||||
|
$blueprint->add('tiktok_shop_vat_rate', 11.0);
|
||||||
|
$blueprint->add('tiktok_shop_url', null);
|
||||||
|
$blueprint->add('tiktok_shop_id', null);
|
||||||
|
|
||||||
|
$blueprint->add('shopee_enabled', true);
|
||||||
|
$blueprint->add('shopee_commission_fee', 6.0);
|
||||||
|
$blueprint->add('shopee_transaction_fee', 2.0);
|
||||||
|
$blueprint->add('shopee_service_fee', 0.0);
|
||||||
|
$blueprint->add('shopee_payment_fee', 0.0);
|
||||||
|
$blueprint->add('shopee_affiliate_commission', 0.0);
|
||||||
|
$blueprint->add('shopee_shipping_subsidy', 0.0);
|
||||||
|
$blueprint->add('shopee_voucher_fee', 0.0);
|
||||||
|
$blueprint->add('shopee_shop_url', null);
|
||||||
|
$blueprint->add('shopee_shop_id', null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Link, usePage } from '@inertiajs/vue3';
|
import { Link, usePage } from '@inertiajs/vue3';
|
||||||
import { Banknote, CalendarDays, Clock, FolderTree, Layers, LayoutDashboard, Package, Receipt, User, UserCheck, Users, Wallet, WalletCards } from '@lucide/vue';
|
import { Banknote, CalendarDays, Clock, FolderTree, Layers, LayoutDashboard, Package, Receipt, Settings2, User, UserCheck, Users, Wallet, WalletCards } from '@lucide/vue';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import {
|
import {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
@ -40,6 +40,8 @@ const showMasterMenu = computed(() => (
|
|||||||
can('categories.view') || can('products.view') || can('raw-materials.view')
|
can('categories.view') || can('products.view') || can('raw-materials.view')
|
||||||
|| can('suppliers.view') || can('customers.view')
|
|| can('suppliers.view') || can('customers.view')
|
||||||
));
|
));
|
||||||
|
const isSettingActive = computed(() => page.url.startsWith('/admin/system/setting'));
|
||||||
|
const showSystemMenu = computed(() => can('settings.view'));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -190,6 +192,21 @@ const showMasterMenu = computed(() => (
|
|||||||
</SidebarMenu>
|
</SidebarMenu>
|
||||||
</SidebarGroupContent>
|
</SidebarGroupContent>
|
||||||
</SidebarGroup>
|
</SidebarGroup>
|
||||||
|
<SidebarGroup v-if="showSystemMenu">
|
||||||
|
<SidebarGroupLabel>Sistem</SidebarGroupLabel>
|
||||||
|
<SidebarGroupContent>
|
||||||
|
<SidebarMenu>
|
||||||
|
<SidebarMenuItem v-if="can('settings.view')">
|
||||||
|
<SidebarMenuButton as-child tooltip="Pengaturan" :is-active="isSettingActive">
|
||||||
|
<Link href="/admin/system/setting">
|
||||||
|
<Settings2 />
|
||||||
|
<span>Pengaturan</span>
|
||||||
|
</Link>
|
||||||
|
</SidebarMenuButton>
|
||||||
|
</SidebarMenuItem>
|
||||||
|
</SidebarMenu>
|
||||||
|
</SidebarGroupContent>
|
||||||
|
</SidebarGroup>
|
||||||
</SidebarContent>
|
</SidebarContent>
|
||||||
<SidebarRail />
|
<SidebarRail />
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|||||||
91
resources/js/components/admin/setting/ImageUploadField.vue
Normal file
91
resources/js/components/admin/setting/ImageUploadField.vue
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ImagePlus, X } from '@lucide/vue';
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Field, FieldDescription, FieldError, FieldLabel } from '@/components/ui/field';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
description?: string;
|
||||||
|
currentUrl?: string | null;
|
||||||
|
errors?: string[];
|
||||||
|
accept?: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const model = defineModel<File | null>();
|
||||||
|
|
||||||
|
const previewUrl = ref<string | null>(null);
|
||||||
|
|
||||||
|
const displayUrl = computed(() => previewUrl.value ?? props.currentUrl ?? null);
|
||||||
|
|
||||||
|
function onFileChange(event: Event) {
|
||||||
|
const input = event.target as HTMLInputElement;
|
||||||
|
const file = input.files?.[0] ?? null;
|
||||||
|
|
||||||
|
if (previewUrl.value) {
|
||||||
|
URL.revokeObjectURL(previewUrl.value);
|
||||||
|
previewUrl.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
model.value = file;
|
||||||
|
previewUrl.value = file ? URL.createObjectURL(file) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearFile() {
|
||||||
|
if (previewUrl.value) {
|
||||||
|
URL.revokeObjectURL(previewUrl.value);
|
||||||
|
previewUrl.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
model.value = null;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Field>
|
||||||
|
<FieldLabel :for="id">
|
||||||
|
{{ label }}
|
||||||
|
</FieldLabel>
|
||||||
|
<FieldDescription v-if="description">
|
||||||
|
{{ description }}
|
||||||
|
</FieldDescription>
|
||||||
|
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div
|
||||||
|
v-if="displayUrl"
|
||||||
|
:class="cn(
|
||||||
|
'relative overflow-hidden rounded-lg border bg-muted/30',
|
||||||
|
id === 'favicon' ? 'size-20' : 'aspect-video max-w-md',
|
||||||
|
)"
|
||||||
|
>
|
||||||
|
<img :src="displayUrl" :alt="label" class="size-full object-cover">
|
||||||
|
<Button
|
||||||
|
v-if="model"
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
size="icon"
|
||||||
|
class="absolute top-2 right-2 size-7"
|
||||||
|
@click="clearFile"
|
||||||
|
>
|
||||||
|
<X class="size-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Input
|
||||||
|
:id="id"
|
||||||
|
type="file"
|
||||||
|
:accept="accept ?? 'image/*'"
|
||||||
|
class="max-w-md cursor-pointer"
|
||||||
|
@change="onFileChange"
|
||||||
|
/>
|
||||||
|
<ImagePlus v-if="!displayUrl" class="text-muted-foreground size-5 shrink-0" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FieldError :errors="errors ?? []" />
|
||||||
|
</Field>
|
||||||
|
</template>
|
||||||
279
resources/js/components/admin/setting/MarketplaceSection.vue
Normal file
279
resources/js/components/admin/setting/MarketplaceSection.vue
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from '@inertiajs/vue3';
|
||||||
|
import { Save, ShoppingBag, Store } from '@lucide/vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { toast } from 'vue-sonner';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Field, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldSet } from '@/components/ui/field';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { Switch } from '@/components/ui/switch';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import type { MarketplacePlatform, MarketplaceSettingsData } from '@/types/setting';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
data: MarketplaceSettingsData;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const activePlatform = ref<MarketplacePlatform>('tiktok_shop');
|
||||||
|
|
||||||
|
const platformItems: Array<{
|
||||||
|
key: MarketplacePlatform;
|
||||||
|
label: string;
|
||||||
|
icon: typeof Store;
|
||||||
|
}> = [
|
||||||
|
{ key: 'tiktok_shop', label: 'TikTok Shop', icon: Store },
|
||||||
|
{ key: 'shopee', label: 'Shopee', icon: ShoppingBag },
|
||||||
|
];
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
tiktok_shop_enabled: props.data.tiktok_shop_enabled,
|
||||||
|
tiktok_shop_admin_fee: props.data.tiktok_shop_admin_fee,
|
||||||
|
tiktok_shop_transaction_fee: props.data.tiktok_shop_transaction_fee,
|
||||||
|
tiktok_shop_payment_fee: props.data.tiktok_shop_payment_fee,
|
||||||
|
tiktok_shop_affiliate_commission: props.data.tiktok_shop_affiliate_commission,
|
||||||
|
tiktok_shop_shipping_subsidy: props.data.tiktok_shop_shipping_subsidy,
|
||||||
|
tiktok_shop_vat_rate: props.data.tiktok_shop_vat_rate,
|
||||||
|
tiktok_shop_url: props.data.tiktok_shop_url ?? '',
|
||||||
|
tiktok_shop_id: props.data.tiktok_shop_id ?? '',
|
||||||
|
|
||||||
|
shopee_enabled: props.data.shopee_enabled,
|
||||||
|
shopee_commission_fee: props.data.shopee_commission_fee,
|
||||||
|
shopee_transaction_fee: props.data.shopee_transaction_fee,
|
||||||
|
shopee_service_fee: props.data.shopee_service_fee,
|
||||||
|
shopee_payment_fee: props.data.shopee_payment_fee,
|
||||||
|
shopee_affiliate_commission: props.data.shopee_affiliate_commission,
|
||||||
|
shopee_shipping_subsidy: props.data.shopee_shipping_subsidy,
|
||||||
|
shopee_voucher_fee: props.data.shopee_voucher_fee,
|
||||||
|
shopee_shop_url: props.data.shopee_shop_url ?? '',
|
||||||
|
shopee_shop_id: props.data.shopee_shop_id ?? '',
|
||||||
|
});
|
||||||
|
|
||||||
|
function submit() {
|
||||||
|
form.put('/admin/system/setting/marketplace', {
|
||||||
|
preserveScroll: true,
|
||||||
|
onError: () => {
|
||||||
|
toast.error('Gagal menyimpan pengaturan marketplace.');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form @submit.prevent="submit">
|
||||||
|
<div class="flex flex-col gap-6 lg:flex-row">
|
||||||
|
<nav class="flex shrink-0 flex-row gap-1 overflow-x-auto lg:w-44 lg:flex-col lg:overflow-visible">
|
||||||
|
<button v-for="item in platformItems" :key="item.key" type="button" :class="cn(
|
||||||
|
'inline-flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium whitespace-nowrap transition-colors',
|
||||||
|
activePlatform === item.key
|
||||||
|
? 'bg-accent text-accent-foreground'
|
||||||
|
: 'text-muted-foreground hover:bg-accent/50 hover:text-accent-foreground',
|
||||||
|
)" @click="activePlatform = item.key">
|
||||||
|
<component :is="item.icon" class="size-4 shrink-0" />
|
||||||
|
{{ item.label }}
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="min-w-0 flex-1 space-y-6">
|
||||||
|
<Card v-show="activePlatform === 'tiktok_shop'">
|
||||||
|
<CardHeader>
|
||||||
|
<div class="flex items-center justify-between gap-4">
|
||||||
|
<div>
|
||||||
|
<CardTitle>TikTok Shop</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Biaya dan konfigurasi penjualan di TikTok Shop.
|
||||||
|
</CardDescription>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Switch id="tiktok_shop_enabled" v-model:checked="form.tiktok_shop_enabled" />
|
||||||
|
<FieldLabel for="tiktok_shop_enabled" class="mb-0 text-sm">
|
||||||
|
Aktif
|
||||||
|
</FieldLabel>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<FieldSet>
|
||||||
|
<FieldGroup class="grid gap-4 sm:grid-cols-2">
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="tiktok_shop_admin_fee">Biaya Admin (%)</FieldLabel>
|
||||||
|
<Input id="tiktok_shop_admin_fee" v-model="form.tiktok_shop_admin_fee" type="number"
|
||||||
|
step="0.01" min="0" max="100" />
|
||||||
|
<FieldDescription>Komisi platform TikTok Shop.</FieldDescription>
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.tiktok_shop_admin_fee ? [form.errors.tiktok_shop_admin_fee] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="tiktok_shop_transaction_fee">Biaya Transaksi (%)</FieldLabel>
|
||||||
|
<Input id="tiktok_shop_transaction_fee" v-model="form.tiktok_shop_transaction_fee"
|
||||||
|
type="number" step="0.01" min="0" max="100" />
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.tiktok_shop_transaction_fee ? [form.errors.tiktok_shop_transaction_fee] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="tiktok_shop_payment_fee">Biaya Pembayaran (%)</FieldLabel>
|
||||||
|
<Input id="tiktok_shop_payment_fee" v-model="form.tiktok_shop_payment_fee"
|
||||||
|
type="number" step="0.01" min="0" max="100" />
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.tiktok_shop_payment_fee ? [form.errors.tiktok_shop_payment_fee] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="tiktok_shop_affiliate_commission">Komisi Afiliasi (%)</FieldLabel>
|
||||||
|
<Input id="tiktok_shop_affiliate_commission"
|
||||||
|
v-model="form.tiktok_shop_affiliate_commission" type="number" step="0.01"
|
||||||
|
min="0" max="100" />
|
||||||
|
<FieldDescription>Biaya jika penjualan via afiliasi/kreator.</FieldDescription>
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.tiktok_shop_affiliate_commission ? [form.errors.tiktok_shop_affiliate_commission] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="tiktok_shop_shipping_subsidy">Subsidi Ongkir (%)</FieldLabel>
|
||||||
|
<Input id="tiktok_shop_shipping_subsidy" v-model="form.tiktok_shop_shipping_subsidy"
|
||||||
|
type="number" step="0.01" min="0" max="100" />
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.tiktok_shop_shipping_subsidy ? [form.errors.tiktok_shop_shipping_subsidy] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="tiktok_shop_vat_rate">PPN / Pajak (%)</FieldLabel>
|
||||||
|
<Input id="tiktok_shop_vat_rate" v-model="form.tiktok_shop_vat_rate" type="number"
|
||||||
|
step="0.01" min="0" max="100" />
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.tiktok_shop_vat_rate ? [form.errors.tiktok_shop_vat_rate] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="tiktok_shop_url">URL Toko</FieldLabel>
|
||||||
|
<Input id="tiktok_shop_url" v-model="form.tiktok_shop_url" type="url"
|
||||||
|
placeholder="https://www.tiktok.com/@toko" />
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.tiktok_shop_url ? [form.errors.tiktok_shop_url] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="tiktok_shop_id">Shop ID</FieldLabel>
|
||||||
|
<Input id="tiktok_shop_id" v-model="form.tiktok_shop_id"
|
||||||
|
placeholder="ID toko TikTok Shop" />
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.tiktok_shop_id ? [form.errors.tiktok_shop_id] : []" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</FieldSet>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card v-show="activePlatform === 'shopee'">
|
||||||
|
<CardHeader>
|
||||||
|
<div class="flex items-center justify-between gap-4">
|
||||||
|
<div>
|
||||||
|
<CardTitle>Shopee</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Biaya dan konfigurasi penjualan di Shopee.
|
||||||
|
</CardDescription>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Switch id="shopee_enabled" v-model:checked="form.shopee_enabled" />
|
||||||
|
<FieldLabel for="shopee_enabled" class="mb-0 text-sm">
|
||||||
|
Aktif
|
||||||
|
</FieldLabel>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<FieldSet>
|
||||||
|
<FieldGroup class="grid gap-4 sm:grid-cols-2">
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="shopee_commission_fee">Komisi Shopee (%)</FieldLabel>
|
||||||
|
<Input id="shopee_commission_fee" v-model="form.shopee_commission_fee" type="number"
|
||||||
|
step="0.01" min="0" max="100" />
|
||||||
|
<FieldDescription>Komisi penjualan kategori umum.</FieldDescription>
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.shopee_commission_fee ? [form.errors.shopee_commission_fee] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="shopee_transaction_fee">Biaya Transaksi (%)</FieldLabel>
|
||||||
|
<Input id="shopee_transaction_fee" v-model="form.shopee_transaction_fee"
|
||||||
|
type="number" step="0.01" min="0" max="100" />
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.shopee_transaction_fee ? [form.errors.shopee_transaction_fee] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="shopee_service_fee">Biaya Layanan (%)</FieldLabel>
|
||||||
|
<Input id="shopee_service_fee" v-model="form.shopee_service_fee" type="number"
|
||||||
|
step="0.01" min="0" max="100" />
|
||||||
|
<FieldDescription>Biaya program Shopee (jika berlaku).</FieldDescription>
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.shopee_service_fee ? [form.errors.shopee_service_fee] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="shopee_payment_fee">Biaya Pembayaran (%)</FieldLabel>
|
||||||
|
<Input id="shopee_payment_fee" v-model="form.shopee_payment_fee" type="number"
|
||||||
|
step="0.01" min="0" max="100" />
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.shopee_payment_fee ? [form.errors.shopee_payment_fee] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="shopee_affiliate_commission">Komisi Afiliasi Shopee (%)
|
||||||
|
</FieldLabel>
|
||||||
|
<Input id="shopee_affiliate_commission" v-model="form.shopee_affiliate_commission"
|
||||||
|
type="number" step="0.01" min="0" max="100" />
|
||||||
|
<FieldDescription>Shopee Affiliate / kolaborasi kreator.</FieldDescription>
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.shopee_affiliate_commission ? [form.errors.shopee_affiliate_commission] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="shopee_shipping_subsidy">Subsidi Ongkir (%)</FieldLabel>
|
||||||
|
<Input id="shopee_shipping_subsidy" v-model="form.shopee_shipping_subsidy"
|
||||||
|
type="number" step="0.01" min="0" max="100" />
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.shopee_shipping_subsidy ? [form.errors.shopee_shipping_subsidy] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="shopee_voucher_fee">Biaya Voucher / Diskon (%)</FieldLabel>
|
||||||
|
<Input id="shopee_voucher_fee" v-model="form.shopee_voucher_fee" type="number"
|
||||||
|
step="0.01" min="0" max="100" />
|
||||||
|
<FieldDescription>Estimasi biaya voucher toko atau campaign.</FieldDescription>
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.shopee_voucher_fee ? [form.errors.shopee_voucher_fee] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="shopee_shop_url">URL Toko</FieldLabel>
|
||||||
|
<Input id="shopee_shop_url" v-model="form.shopee_shop_url" type="url"
|
||||||
|
placeholder="https://shopee.co.id/namatoko" />
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.shopee_shop_url ? [form.errors.shopee_shop_url] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="shopee_shop_id">Shop ID</FieldLabel>
|
||||||
|
<Input id="shopee_shop_id" v-model="form.shopee_shop_id"
|
||||||
|
placeholder="ID toko Shopee" />
|
||||||
|
<FieldError
|
||||||
|
:errors="form.errors.shopee_shop_id ? [form.errors.shopee_shop_id] : []" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</FieldSet>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<Button type="submit" :disabled="form.processing">
|
||||||
|
<Save class="size-4" />
|
||||||
|
{{ form.processing ? 'Menyimpan...' : 'Simpan' }}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
81
resources/js/components/admin/setting/SocialMediaSection.vue
Normal file
81
resources/js/components/admin/setting/SocialMediaSection.vue
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from '@inertiajs/vue3';
|
||||||
|
import { Save } from '@lucide/vue';
|
||||||
|
import { toast } from 'vue-sonner';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Field, FieldError, FieldGroup, FieldLabel, FieldSet } from '@/components/ui/field';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import type { SocialMediaSettingsData } from '@/types/setting';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
data: SocialMediaSettingsData;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
instagram_url: props.data.instagram_url ?? '',
|
||||||
|
facebook_url: props.data.facebook_url ?? '',
|
||||||
|
tiktok_url: props.data.tiktok_url ?? '',
|
||||||
|
});
|
||||||
|
|
||||||
|
function submit() {
|
||||||
|
form.put('/admin/system/setting/social-media', {
|
||||||
|
preserveScroll: true,
|
||||||
|
onError: () => {
|
||||||
|
toast.error('Gagal menyimpan pengaturan media sosial.');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form @submit.prevent="submit">
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Media Sosial</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Tautan profil media sosial yang ditampilkan di website atau aplikasi.
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<FieldSet>
|
||||||
|
<FieldGroup class="grid gap-4">
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="instagram_url">
|
||||||
|
Instagram
|
||||||
|
</FieldLabel>
|
||||||
|
<Input id="instagram_url" v-model="form.instagram_url" type="url"
|
||||||
|
placeholder="https://instagram.com/username" />
|
||||||
|
<FieldError :errors="form.errors.instagram_url ? [form.errors.instagram_url] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="facebook_url">
|
||||||
|
Facebook
|
||||||
|
</FieldLabel>
|
||||||
|
<Input id="facebook_url" v-model="form.facebook_url" type="url"
|
||||||
|
placeholder="https://facebook.com/pagename" />
|
||||||
|
<FieldError :errors="form.errors.facebook_url ? [form.errors.facebook_url] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="tiktok_url">
|
||||||
|
TikTok
|
||||||
|
</FieldLabel>
|
||||||
|
<Input id="tiktok_url" v-model="form.tiktok_url" type="url"
|
||||||
|
placeholder="https://tiktok.com/@username" />
|
||||||
|
<FieldError :errors="form.errors.tiktok_url ? [form.errors.tiktok_url] : []" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</FieldSet>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<div class="mt-6 flex justify-end">
|
||||||
|
<Button type="submit" :disabled="form.processing">
|
||||||
|
<Save class="size-4" />
|
||||||
|
{{ form.processing ? 'Menyimpan...' : 'Simpan' }}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
116
resources/js/components/admin/setting/SystemSection.vue
Normal file
116
resources/js/components/admin/setting/SystemSection.vue
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useForm } from '@inertiajs/vue3';
|
||||||
|
import { Save } from '@lucide/vue';
|
||||||
|
import { toast } from 'vue-sonner';
|
||||||
|
import ImageUploadField from '@/components/admin/setting/ImageUploadField.vue';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Field, FieldError, FieldGroup, FieldLabel, FieldSet } from '@/components/ui/field';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { PhoneNumberInput } from '@/components/ui/phone-number-input';
|
||||||
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
|
import type { SystemSettingsData } from '@/types/setting';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
data: SystemSettingsData;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
app_name: props.data.app_name,
|
||||||
|
about_app: props.data.about_app ?? '',
|
||||||
|
email: props.data.email ?? '',
|
||||||
|
phone: props.data.phone ?? '',
|
||||||
|
logo: null as File | null,
|
||||||
|
login_cover: null as File | null,
|
||||||
|
});
|
||||||
|
|
||||||
|
function submit() {
|
||||||
|
form.post('/admin/system/setting/system', {
|
||||||
|
forceFormData: true,
|
||||||
|
preserveScroll: true,
|
||||||
|
onError: () => {
|
||||||
|
toast.error('Gagal menyimpan pengaturan sistem.');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form @submit.prevent="submit">
|
||||||
|
<div class="grid gap-6">
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Informasi Aplikasi</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Nama, deskripsi, dan kontak yang ditampilkan di aplikasi.
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<FieldSet>
|
||||||
|
<FieldGroup class="grid gap-4 sm:grid-cols-2">
|
||||||
|
<Field class="sm:col-span-2">
|
||||||
|
<FieldLabel for="app_name" required>
|
||||||
|
Nama Aplikasi
|
||||||
|
</FieldLabel>
|
||||||
|
<Input id="app_name" v-model="form.app_name" placeholder="DST Collection" />
|
||||||
|
<FieldError :errors="form.errors.app_name ? [form.errors.app_name] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field class="sm:col-span-2">
|
||||||
|
<FieldLabel for="about_app">
|
||||||
|
Tentang Aplikasi
|
||||||
|
</FieldLabel>
|
||||||
|
<Textarea id="about_app" v-model="form.about_app" rows="4"
|
||||||
|
placeholder="Deskripsi singkat tentang bisnis atau aplikasi Anda." />
|
||||||
|
<FieldError :errors="form.errors.about_app ? [form.errors.about_app] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="email">
|
||||||
|
Email
|
||||||
|
</FieldLabel>
|
||||||
|
<Input id="email" v-model="form.email" type="email" placeholder="info@perusahaan.com" />
|
||||||
|
<FieldError :errors="form.errors.email ? [form.errors.email] : []" />
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field>
|
||||||
|
<FieldLabel for="phone">
|
||||||
|
Nomor Telepon
|
||||||
|
</FieldLabel>
|
||||||
|
<PhoneNumberInput id="phone" v-model="form.phone" />
|
||||||
|
<FieldError :errors="form.errors.phone ? [form.errors.phone] : []" />
|
||||||
|
</Field>
|
||||||
|
</FieldGroup>
|
||||||
|
</FieldSet>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle>Branding</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
Logo aplikasi dan gambar latar halaman login.
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<FieldGroup class="grid gap-6 sm:grid-cols-2">
|
||||||
|
<ImageUploadField id="logo" v-model="form.logo" label="Logo"
|
||||||
|
description="Disarankan PNG transparan, maks. 2 MB." :current-url="data.logo_url"
|
||||||
|
:errors="form.errors.logo ? [form.errors.logo] : []" />
|
||||||
|
|
||||||
|
<ImageUploadField id="login_cover" v-model="form.login_cover" label="Cover Login"
|
||||||
|
description="Gambar latar halaman login, maks. 5 MB." :current-url="data.login_cover_url"
|
||||||
|
:errors="form.errors.login_cover ? [form.errors.login_cover] : []" />
|
||||||
|
</FieldGroup>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<Button type="submit" :disabled="form.processing">
|
||||||
|
<Save class="size-4" />
|
||||||
|
{{ form.processing ? 'Menyimpan...' : 'Simpan' }}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
48
resources/js/layouts/SettingLayout.vue
Normal file
48
resources/js/layouts/SettingLayout.vue
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Settings2, Share2, ShoppingBag } from '@lucide/vue';
|
||||||
|
import AdminLayout from '@/layouts/AdminLayout.vue';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import type { SettingSection } from '@/types/setting';
|
||||||
|
|
||||||
|
const activeSection = defineModel<SettingSection>('section', { required: true });
|
||||||
|
|
||||||
|
const navItems: Array<{
|
||||||
|
key: SettingSection;
|
||||||
|
label: string;
|
||||||
|
icon: typeof Settings2;
|
||||||
|
}> = [
|
||||||
|
{ key: 'system', label: 'Sistem', icon: Settings2 },
|
||||||
|
{ key: 'social', label: 'Media Sosial', icon: Share2 },
|
||||||
|
{ key: 'marketplace', label: 'Marketplace', icon: ShoppingBag },
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<AdminLayout>
|
||||||
|
<div class="space-y-6">
|
||||||
|
<div class="space-y-1">
|
||||||
|
<h2 class="text-2xl font-bold tracking-tight">
|
||||||
|
Pengaturan
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-6 lg:flex-row">
|
||||||
|
<nav class="flex shrink-0 flex-row gap-1 overflow-x-auto lg:w-56 lg:flex-col lg:overflow-visible">
|
||||||
|
<button v-for="item in navItems" :key="item.key" type="button" :class="cn(
|
||||||
|
'inline-flex items-center gap-2 rounded-md px-3 py-2 text-sm font-medium whitespace-nowrap transition-colors',
|
||||||
|
activeSection === item.key
|
||||||
|
? 'bg-accent text-accent-foreground'
|
||||||
|
: 'text-muted-foreground hover:bg-accent/50 hover:text-accent-foreground',
|
||||||
|
)" @click="activeSection = item.key">
|
||||||
|
<component :is="item.icon" class="size-4 shrink-0" />
|
||||||
|
{{ item.label }}
|
||||||
|
</button>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="min-w-0 flex-1">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AdminLayout>
|
||||||
|
</template>
|
||||||
33
resources/js/pages/admin/system/setting/Index.vue
Normal file
33
resources/js/pages/admin/system/setting/Index.vue
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { Head } from '@inertiajs/vue3';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import MarketplaceSection from '@/components/admin/setting/MarketplaceSection.vue';
|
||||||
|
import SocialMediaSection from '@/components/admin/setting/SocialMediaSection.vue';
|
||||||
|
import SystemSection from '@/components/admin/setting/SystemSection.vue';
|
||||||
|
import SettingLayout from '@/layouts/SettingLayout.vue';
|
||||||
|
import type {
|
||||||
|
MarketplaceSettingsData,
|
||||||
|
SettingSection,
|
||||||
|
SocialMediaSettingsData,
|
||||||
|
SystemSettingsData,
|
||||||
|
} from '@/types/setting';
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
system: SystemSettingsData;
|
||||||
|
socialMedia: SocialMediaSettingsData;
|
||||||
|
marketplace: MarketplaceSettingsData;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const activeSection = ref<SettingSection>('system');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<Head title="Pengaturan" />
|
||||||
|
|
||||||
|
<SettingLayout v-model:section="activeSection">
|
||||||
|
<SystemSection v-if="activeSection === 'system'" :data="system" />
|
||||||
|
<SocialMediaSection v-else-if="activeSection === 'social'" :data="socialMedia" />
|
||||||
|
<MarketplaceSection v-else-if="activeSection === 'marketplace'" :data="marketplace" />
|
||||||
|
</SettingLayout>
|
||||||
|
</template>
|
||||||
42
resources/js/types/setting.ts
Normal file
42
resources/js/types/setting.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
export type SettingSection = 'system' | 'social' | 'marketplace';
|
||||||
|
|
||||||
|
export type MarketplacePlatform = 'tiktok_shop' | 'shopee';
|
||||||
|
|
||||||
|
export type SystemSettingsData = {
|
||||||
|
app_name: string;
|
||||||
|
about_app: string | null;
|
||||||
|
email: string | null;
|
||||||
|
phone: string | null;
|
||||||
|
logo: string | null;
|
||||||
|
logo_url: string | null;
|
||||||
|
login_cover: string | null;
|
||||||
|
login_cover_url: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SocialMediaSettingsData = {
|
||||||
|
instagram_url: string | null;
|
||||||
|
facebook_url: string | null;
|
||||||
|
tiktok_url: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MarketplaceSettingsData = {
|
||||||
|
tiktok_shop_enabled: boolean;
|
||||||
|
tiktok_shop_admin_fee: number;
|
||||||
|
tiktok_shop_transaction_fee: number;
|
||||||
|
tiktok_shop_payment_fee: number;
|
||||||
|
tiktok_shop_affiliate_commission: number;
|
||||||
|
tiktok_shop_shipping_subsidy: number;
|
||||||
|
tiktok_shop_vat_rate: number;
|
||||||
|
tiktok_shop_url: string | null;
|
||||||
|
tiktok_shop_id: string | null;
|
||||||
|
shopee_enabled: boolean;
|
||||||
|
shopee_commission_fee: number;
|
||||||
|
shopee_transaction_fee: number;
|
||||||
|
shopee_service_fee: number;
|
||||||
|
shopee_payment_fee: number;
|
||||||
|
shopee_affiliate_commission: number;
|
||||||
|
shopee_shipping_subsidy: number;
|
||||||
|
shopee_voucher_fee: number;
|
||||||
|
shopee_shop_url: string | null;
|
||||||
|
shopee_shop_id: string | null;
|
||||||
|
};
|
||||||
@ -18,6 +18,7 @@
|
|||||||
use App\Http\Controllers\Admin\Master\ProductController;
|
use App\Http\Controllers\Admin\Master\ProductController;
|
||||||
use App\Http\Controllers\Admin\Master\RawMaterialController;
|
use App\Http\Controllers\Admin\Master\RawMaterialController;
|
||||||
use App\Http\Controllers\Admin\Master\SupplierController;
|
use App\Http\Controllers\Admin\Master\SupplierController;
|
||||||
|
use App\Http\Controllers\Admin\System\SettingController;
|
||||||
use App\Http\Controllers\Auth\LoginController;
|
use App\Http\Controllers\Auth\LoginController;
|
||||||
use App\Http\Controllers\Auth\LogoutController;
|
use App\Http\Controllers\Auth\LogoutController;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
@ -153,6 +154,26 @@
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::prefix('system')->name('system.')->group(function () {
|
||||||
|
Route::prefix('setting')->name('setting.')
|
||||||
|
->middleware('permission:'.Permission::SETTINGS_VIEW->value)
|
||||||
|
->group(function () {
|
||||||
|
Route::get('/', [SettingController::class, 'index'])->name('index');
|
||||||
|
|
||||||
|
Route::post('system', [SettingController::class, 'updateSystem'])
|
||||||
|
->middleware('permission:'.Permission::SETTINGS_UPDATE->value)
|
||||||
|
->name('system.update');
|
||||||
|
|
||||||
|
Route::put('social-media', [SettingController::class, 'updateSocialMedia'])
|
||||||
|
->middleware('permission:'.Permission::SETTINGS_UPDATE->value)
|
||||||
|
->name('social-media.update');
|
||||||
|
|
||||||
|
Route::put('marketplace', [SettingController::class, 'updateMarketplace'])
|
||||||
|
->middleware('permission:'.Permission::SETTINGS_UPDATE->value)
|
||||||
|
->name('marketplace.update');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
Route::prefix('account')->name('account.')->group(function () {
|
Route::prefix('account')->name('account.')->group(function () {
|
||||||
Route::get('profile', [ProfileController::class, 'edit'])->name('profile');
|
Route::get('profile', [ProfileController::class, 'edit'])->name('profile');
|
||||||
Route::put('profile', [ProfileController::class, 'update'])->name('profile.update');
|
Route::put('profile', [ProfileController::class, 'update'])->name('profile.update');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user