From 2b7208a0c46268fd319f63e2b7920d1c504121f9 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sat, 4 Jul 2026 13:37:26 +0700 Subject: [PATCH] feat: expand permission management for settings by introducing new permissions for system, social media, marketplace, HR, and homepage updates; refactor related controllers, requests, and services to utilize these permissions; enhance frontend components to support new permission checks and improve user experience --- app/Enums/Permission.php | 30 ++++- app/Enums/Role.php | 12 +- .../Admin/System/SettingController.php | 26 ++--- .../System/Setting/HomepageSettingRequest.php | 4 +- .../Admin/System/Setting/HrSettingRequest.php | 2 +- .../System/Setting/MarketplaceRequest.php | 2 +- .../System/Setting/SocialMediaRequest.php | 2 +- .../Admin/System/Setting/SystemRequest.php | 2 +- .../System/Setting/HomepageSettingService.php | 63 ++++++---- .../System/Setting/MarketplaceService.php | 109 ++++++++++-------- app/Services/System/Setting/SystemService.php | 96 +++++++++------ resources/js/components/AppSidebar.vue | 15 ++- resources/js/composables/useCan.ts | 5 +- .../js/pages/admin/system/setting/Index.vue | 15 ++- .../system/setting/form/HomepageSection.vue | 3 +- .../admin/system/setting/form/HrSection.vue | 3 +- .../setting/form/MarketplaceSection.vue | 3 +- .../setting/form/SocialMediaSection.vue | 3 +- .../system/setting/form/SystemSection.vue | 3 +- routes/web.php | 12 +- tests/Feature/Admin/System/SettingTest.php | 80 ++++++------- 21 files changed, 296 insertions(+), 194 deletions(-) diff --git a/app/Enums/Permission.php b/app/Enums/Permission.php index b753360..57f4ac6 100644 --- a/app/Enums/Permission.php +++ b/app/Enums/Permission.php @@ -135,8 +135,16 @@ enum Permission: string case PAYROLL_VIEW = 'payroll.view'; case PAYROLL_ADJUST = 'payroll.adjust'; - case SETTINGS_VIEW = 'settings.view'; - case SETTINGS_UPDATE = 'settings.update'; + case SETTINGS_VIEW_SYSTEM = 'settings.view_system'; + case SETTINGS_UPDATE_SYSTEM = 'settings.update_system'; + case SETTINGS_VIEW_SOCIAL_MEDIA = 'settings.view_social_media'; + case SETTINGS_UPDATE_SOCIAL_MEDIA = 'settings.update_social_media'; + case SETTINGS_VIEW_MARKETPLACE = 'settings.view_marketplace'; + case SETTINGS_UPDATE_MARKETPLACE = 'settings.update_marketplace'; + case SETTINGS_VIEW_HR = 'settings.view_hr'; + case SETTINGS_UPDATE_HR = 'settings.update_hr'; + case SETTINGS_VIEW_HOMEPAGE = 'settings.view_homepage'; + case SETTINGS_UPDATE_HOMEPAGE = 'settings.update_homepage'; case ACTIVITY_LOGS_VIEW = 'activity_logs.view'; @@ -275,8 +283,16 @@ public function label(): string self::PAYROLL_VIEW => 'Lihat Gaji', self::PAYROLL_ADJUST => 'Sesuaikan Gaji', - self::SETTINGS_VIEW => 'Lihat Pengaturan Aplikasi', - self::SETTINGS_UPDATE => 'Ubah Pengaturan Aplikasi', + self::SETTINGS_VIEW_SYSTEM => 'Lihat Pengaturan Sistem', + self::SETTINGS_UPDATE_SYSTEM => 'Ubah Pengaturan Sistem', + self::SETTINGS_VIEW_SOCIAL_MEDIA => 'Lihat Pengaturan Media Sosial', + self::SETTINGS_UPDATE_SOCIAL_MEDIA => 'Ubah Pengaturan Media Sosial', + self::SETTINGS_VIEW_MARKETPLACE => 'Lihat Pengaturan Marketplace', + self::SETTINGS_UPDATE_MARKETPLACE => 'Ubah Pengaturan Marketplace', + self::SETTINGS_VIEW_HR => 'Lihat Pengaturan HR', + self::SETTINGS_UPDATE_HR => 'Ubah Pengaturan HR', + self::SETTINGS_VIEW_HOMEPAGE => 'Lihat Pengaturan Homepage', + self::SETTINGS_UPDATE_HOMEPAGE => 'Ubah Pengaturan Homepage', self::ACTIVITY_LOGS_VIEW => 'Lihat Log Aktivitas', @@ -335,7 +351,11 @@ public function group(): string self::EMPLOYEE_ADVANCES_DELETE, self::EMPLOYEE_ADVANCES_VERIFY, self::EMPLOYEE_ADVANCES_PAY => 'Kasbon', self::PAYROLL_VIEW, self::PAYROLL_ADJUST => 'Gaji', - self::SETTINGS_VIEW, self::SETTINGS_UPDATE => 'Pengaturan Aplikasi', + self::SETTINGS_VIEW_SYSTEM, self::SETTINGS_UPDATE_SYSTEM, + self::SETTINGS_VIEW_SOCIAL_MEDIA, self::SETTINGS_UPDATE_SOCIAL_MEDIA, + self::SETTINGS_VIEW_MARKETPLACE, self::SETTINGS_UPDATE_MARKETPLACE, + self::SETTINGS_VIEW_HR, self::SETTINGS_UPDATE_HR, + self::SETTINGS_VIEW_HOMEPAGE, self::SETTINGS_UPDATE_HOMEPAGE => 'Pengaturan Aplikasi', self::ACTIVITY_LOGS_VIEW => 'Log Aktivitas', self::ROLES_VIEW, self::ROLES_CREATE, self::ROLES_UPDATE, self::ROLES_DELETE => 'Role & Permission', diff --git a/app/Enums/Role.php b/app/Enums/Role.php index 0644237..17d44f0 100644 --- a/app/Enums/Role.php +++ b/app/Enums/Role.php @@ -193,8 +193,16 @@ public function permissions(): array Permission::PAYROLL_VIEW, Permission::PAYROLL_ADJUST, - Permission::SETTINGS_VIEW, - Permission::SETTINGS_UPDATE, + Permission::SETTINGS_VIEW_SYSTEM, + Permission::SETTINGS_UPDATE_SYSTEM, + Permission::SETTINGS_VIEW_SOCIAL_MEDIA, + Permission::SETTINGS_UPDATE_SOCIAL_MEDIA, + Permission::SETTINGS_VIEW_MARKETPLACE, + Permission::SETTINGS_UPDATE_MARKETPLACE, + Permission::SETTINGS_VIEW_HR, + Permission::SETTINGS_UPDATE_HR, + Permission::SETTINGS_VIEW_HOMEPAGE, + Permission::SETTINGS_UPDATE_HOMEPAGE, ], self::CASHIER => [ diff --git a/app/Http/Controllers/Admin/System/SettingController.php b/app/Http/Controllers/Admin/System/SettingController.php index fb86f86..e1762cd 100644 --- a/app/Http/Controllers/Admin/System/SettingController.php +++ b/app/Http/Controllers/Admin/System/SettingController.php @@ -17,6 +17,7 @@ use App\Services\System\Setting\SocialMediaService; use App\Services\System\Setting\SystemService; use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; use Inertia\Inertia; use Inertia\Response; @@ -33,8 +34,10 @@ public function __construct( private readonly OwnerVerificationService $ownerVerificationService, ) {} - public function index(): Response + public function index(Request $request): Response { + $user = $request->user(); + return Inertia::render('admin/system/setting/Index', [ 'system' => $this->systemService->systemData(), 'socialMedia' => $this->socialMediaService->socialMediaData(), @@ -42,15 +45,16 @@ public function index(): Response 'hr' => $this->hrSettingService->hrData(), 'homepage' => $this->homepageSettingService->homepageData(), 'hasPendingMarketplaceVerification' => $this->ownerVerificationService->hasPendingMarketplaceVerification(), + 'canUpdateSystem' => $user->can(Permission::SETTINGS_UPDATE_SYSTEM->value), + 'canUpdateSocialMedia' => $user->can(Permission::SETTINGS_UPDATE_SOCIAL_MEDIA->value), + 'canUpdateMarketplace' => $user->can(Permission::SETTINGS_UPDATE_MARKETPLACE->value), + 'canUpdateHr' => $user->can(Permission::SETTINGS_UPDATE_HR->value), + 'canUpdateHomepage' => $user->can(Permission::SETTINGS_UPDATE_HOMEPAGE->value), ]); } public function updateSystem(SystemRequest $request): RedirectResponse { - if (! $request->user()->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) { - abort(403, 'Aksi ini tidak diizinkan.'); - } - $this->systemService->updateSystem($request->validated()); $this->flashSuccess('Pengaturan sistem berhasil disimpan.'); @@ -60,10 +64,6 @@ public function updateSystem(SystemRequest $request): RedirectResponse public function updateSocialMedia(SocialMediaRequest $request): RedirectResponse { - if (! $request->user()->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) { - abort(403, 'Aksi ini tidak diizinkan.'); - } - $this->socialMediaService->updateSocialMedia($request->validated()); $this->flashSuccess('Pengaturan media sosial berhasil disimpan.'); @@ -86,10 +86,6 @@ public function updateMarketplace(MarketplaceRequest $request): RedirectResponse public function updateHr(HrSettingRequest $request): RedirectResponse { - if (! $request->user()->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) { - abort(403, 'Aksi ini tidak diizinkan.'); - } - $this->hrSettingService->updateHr($request->validated()); $this->flashSuccess('Pengaturan HR berhasil disimpan.'); @@ -99,10 +95,6 @@ public function updateHr(HrSettingRequest $request): RedirectResponse public function updateHomepage(HomepageSettingRequest $request): RedirectResponse { - if (! $request->user()->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) { - abort(403, 'Aksi ini tidak diizinkan.'); - } - $this->homepageSettingService->updateHomepage($request->validated()); $this->flashSuccess('Pengaturan homepage berhasil disimpan.'); diff --git a/app/Http/Requests/Admin/System/Setting/HomepageSettingRequest.php b/app/Http/Requests/Admin/System/Setting/HomepageSettingRequest.php index cb71f22..ff755e5 100644 --- a/app/Http/Requests/Admin/System/Setting/HomepageSettingRequest.php +++ b/app/Http/Requests/Admin/System/Setting/HomepageSettingRequest.php @@ -9,7 +9,7 @@ class HomepageSettingRequest extends FormRequest { public function authorize(): bool { - return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false; + return $this->user()?->can(Permission::SETTINGS_UPDATE_HOMEPAGE->value) ?? false; } /** @@ -24,6 +24,8 @@ public function rules(): array 'about_image_s3_key' => ['nullable', 'string'], 'gallery_s3_keys' => ['nullable', 'array', 'max:10'], 'gallery_s3_keys.*' => ['required', 'string'], + 'gallery_images' => ['nullable', 'array', 'max:10'], + 'gallery_images.*' => ['required', 'image', 'max:5120'], 'gallery_images_remove' => ['nullable', 'array'], 'gallery_images_remove.*' => ['integer'], ]; diff --git a/app/Http/Requests/Admin/System/Setting/HrSettingRequest.php b/app/Http/Requests/Admin/System/Setting/HrSettingRequest.php index c8096a4..1bfb4f6 100644 --- a/app/Http/Requests/Admin/System/Setting/HrSettingRequest.php +++ b/app/Http/Requests/Admin/System/Setting/HrSettingRequest.php @@ -9,7 +9,7 @@ class HrSettingRequest extends FormRequest { public function authorize(): bool { - return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false; + return $this->user()?->can(Permission::SETTINGS_UPDATE_HR->value) ?? false; } /** diff --git a/app/Http/Requests/Admin/System/Setting/MarketplaceRequest.php b/app/Http/Requests/Admin/System/Setting/MarketplaceRequest.php index c3bf976..0b228d6 100644 --- a/app/Http/Requests/Admin/System/Setting/MarketplaceRequest.php +++ b/app/Http/Requests/Admin/System/Setting/MarketplaceRequest.php @@ -13,7 +13,7 @@ class MarketplaceRequest extends FormRequest { public function authorize(): bool { - return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false; + return $this->user()?->can(Permission::SETTINGS_UPDATE_MARKETPLACE->value) ?? false; } /** diff --git a/app/Http/Requests/Admin/System/Setting/SocialMediaRequest.php b/app/Http/Requests/Admin/System/Setting/SocialMediaRequest.php index dd17d06..698c0a3 100644 --- a/app/Http/Requests/Admin/System/Setting/SocialMediaRequest.php +++ b/app/Http/Requests/Admin/System/Setting/SocialMediaRequest.php @@ -9,7 +9,7 @@ class SocialMediaRequest extends FormRequest { public function authorize(): bool { - return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false; + return $this->user()?->can(Permission::SETTINGS_UPDATE_SOCIAL_MEDIA->value) ?? false; } /** diff --git a/app/Http/Requests/Admin/System/Setting/SystemRequest.php b/app/Http/Requests/Admin/System/Setting/SystemRequest.php index f1f796c..ba9eb78 100644 --- a/app/Http/Requests/Admin/System/Setting/SystemRequest.php +++ b/app/Http/Requests/Admin/System/Setting/SystemRequest.php @@ -10,7 +10,7 @@ class SystemRequest extends FormRequest { public function authorize(): bool { - return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false; + return $this->user()?->can(Permission::SETTINGS_UPDATE_SYSTEM->value) ?? false; } /** diff --git a/app/Services/System/Setting/HomepageSettingService.php b/app/Services/System/Setting/HomepageSettingService.php index bf2f117..a55124b 100644 --- a/app/Services/System/Setting/HomepageSettingService.php +++ b/app/Services/System/Setting/HomepageSettingService.php @@ -3,12 +3,16 @@ namespace App\Services\System\Setting; use App\Models\HomepageConfiguration; +use App\Services\Concerns\RunsInTransaction; +use App\Services\Concerns\SyncsPhotos; use App\Services\Media\MediaService; use App\Support\Media\MediaPresenter; use Illuminate\Http\UploadedFile; class HomepageSettingService { + use RunsInTransaction, SyncsPhotos; + public function __construct( private readonly MediaService $mediaService, ) {} @@ -31,30 +35,45 @@ public function homepageData(): array public function updateHomepage(array $validated): void { - $configuration = HomepageConfiguration::instance(); + $this->runInTransaction( + function () use ($validated): void { + $configuration = HomepageConfiguration::instance(); - if (isset($validated['hero_image_s3_key'])) { - $this->mediaService->replaceSingleS3Key($configuration, $validated['hero_image_s3_key'], 'hero_image', 'hero-image'); - } elseif (isset($validated['hero_image']) && $validated['hero_image'] instanceof UploadedFile) { - $this->mediaService->replaceSingleFile($configuration, $validated['hero_image'], 'hero_image', 'hero-image'); - } + $this->syncPhotos( + $configuration, + [ + 'photos' => isset($validated['hero_image']) ? [$validated['hero_image']] : null, + 's3_keys' => isset($validated['hero_image_s3_key']) ? [$validated['hero_image_s3_key']] : null, + ], + maxPhotos: 1, + required: false, + collection: 'hero_image', + ); - if (isset($validated['about_image_s3_key'])) { - $this->mediaService->replaceSingleS3Key($configuration, $validated['about_image_s3_key'], 'about_image', 'about-image'); - } elseif (isset($validated['about_image']) && $validated['about_image'] instanceof UploadedFile) { - $this->mediaService->replaceSingleFile($configuration, $validated['about_image'], 'about_image', 'about-image'); - } + $this->syncPhotos( + $configuration, + [ + 'photos' => isset($validated['about_image']) ? [$validated['about_image']] : null, + 's3_keys' => isset($validated['about_image_s3_key']) ? [$validated['about_image_s3_key']] : null, + ], + maxPhotos: 1, + required: false, + collection: 'about_image', + ); - if (isset($validated['gallery_s3_keys']) || isset($validated['gallery_images_remove'])) { - $this->mediaService->syncCollection( - $configuration, - 'gallery', - null, - $validated['gallery_images_remove'] ?? null, - 10, - 'gallery', - s3Keys: $validated['gallery_s3_keys'] ?? null, - ); - } + $this->syncPhotos( + $configuration, + [ + 'photos' => $validated['gallery_images'] ?? null, + 'remove_media_ids' => $validated['gallery_images_remove'] ?? null, + 's3_keys' => $validated['gallery_s3_keys'] ?? null, + ], + maxPhotos: 10, + required: false, + collection: 'gallery', + ); + }, + 'Gagal memperbarui pengaturan homepage', + ); } } diff --git a/app/Services/System/Setting/MarketplaceService.php b/app/Services/System/Setting/MarketplaceService.php index a3d3d8b..779d6bc 100644 --- a/app/Services/System/Setting/MarketplaceService.php +++ b/app/Services/System/Setting/MarketplaceService.php @@ -8,6 +8,7 @@ use App\Enums\Permission; use App\Models\OwnerVerificationRequest; use App\Models\User; +use App\Services\Concerns\RunsInTransaction; use App\Services\System\PushNotificationService; use App\Settings\MarketplaceSettings; use App\Support\Marketplace\MarketplaceFeeCalculator; @@ -16,6 +17,8 @@ class MarketplaceService { + use RunsInTransaction; + public function __construct( private readonly PushNotificationService $pushNotificationService, ) {} @@ -72,61 +75,66 @@ public function marketplaceData(): array public function updateMarketplace(array $validated, User $user): void { - if ($user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) { - $this->saveSettings($validated); + $this->runInTransaction( + function () use ($validated, $user): void { + if ($user->can(Permission::OWNER_VERIFICATIONS_VERIFY->value)) { + $this->saveSettings($validated); - return; - } + return; + } - $hasPending = OwnerVerificationRequest::query() - ->where('subject_type', MarketplaceSettings::class) - ->pending() - ->exists(); + $hasPending = OwnerVerificationRequest::query() + ->where('subject_type', MarketplaceSettings::class) + ->pending() + ->exists(); - if ($hasPending) { - throw ValidationException::withMessages([ - 'system' => 'Perubahan pengaturan marketplace sedang menunggu verifikasi owner.', - ]); - } + if ($hasPending) { + throw ValidationException::withMessages([ + 'system' => 'Perubahan pengaturan marketplace sedang menunggu verifikasi owner.', + ]); + } - $settings = app(MarketplaceSettings::class); - $oldPayload = []; - $newPayload = []; + $settings = app(MarketplaceSettings::class); + $oldPayload = []; + $newPayload = []; - foreach ($this->tiktokFeeKeys() as $key) { - $oldPayload[$key] = $this->presentFeeRule($settings->{$key}); - $newPayload[$key] = $this->normalizeFeeRule($validated[$key]); - } + foreach ($this->tiktokFeeKeys() as $key) { + $oldPayload[$key] = $this->presentFeeRule($settings->{$key}); + $newPayload[$key] = $this->normalizeFeeRule($validated[$key]); + } - foreach ($this->shopeeFeeKeys() as $key) { - $oldPayload[$key] = $this->presentFeeRule($settings->{$key}); - $newPayload[$key] = $this->normalizeFeeRule($validated[$key]); - } + foreach ($this->shopeeFeeKeys() as $key) { + $oldPayload[$key] = $this->presentFeeRule($settings->{$key}); + $newPayload[$key] = $this->normalizeFeeRule($validated[$key]); + } - OwnerVerificationRequest::create([ - 'action' => OwnerVerificationAction::UPDATE, - 'status' => OwnerVerificationStatus::PENDING, - 'subject_type' => MarketplaceSettings::class, - 'subject_id' => null, - 'submitted_by_id' => $user->id, - 'payload' => [ - 'old' => $oldPayload, - 'new' => $newPayload, - ], - ]); + OwnerVerificationRequest::create([ + 'action' => OwnerVerificationAction::UPDATE, + 'status' => OwnerVerificationStatus::PENDING, + 'subject_type' => MarketplaceSettings::class, + 'subject_id' => null, + 'submitted_by_id' => $user->id, + 'payload' => [ + 'old' => $oldPayload, + 'new' => $newPayload, + ], + ]); - $this->pushNotificationService->sendToRoles( - '⚙️ Pengaturan Marketplace Menunggu Persetujuan Owner', - "Pengajuan ubah pengaturan marketplace oleh '{$user->username}' menunggu verifikasi owner.", - ['owner', 'developer', 'direktur'], - route('admin.system.settings.index'), - ); + $this->pushNotificationService->sendToRoles( + '⚙️ Pengaturan Marketplace Menunggu Persetujuan Owner', + "Pengajuan ubah pengaturan marketplace oleh '{$user->username}' menunggu verifikasi owner.", + ['owner', 'developer', 'direktur'], + route('admin.system.settings.index'), + ); - $this->pushNotificationService->sendToUser( - '📤 Pengajuan Terkirim', - 'Pengajuan ubah pengaturan marketplace menunggu verifikasi owner.', - $user->id, - route('admin.system.settings.index'), + $this->pushNotificationService->sendToUser( + '📤 Pengajuan Terkirim', + 'Pengajuan ubah pengaturan marketplace menunggu verifikasi owner.', + $user->id, + route('admin.system.settings.index'), + ); + }, + 'Gagal memperbarui pengaturan marketplace', ); } @@ -147,8 +155,13 @@ public function saveSettings(array $validated): void public function applyVerificationRequest(OwnerVerificationRequest $request): void { - $newPayload = $request->payload['new'] ?? []; - $this->saveSettings($newPayload); + $this->runInTransaction( + function () use ($request): void { + $newPayload = $request->payload['new'] ?? []; + $this->saveSettings($newPayload); + }, + 'Gagal menerapkan pengajuan verifikasi owner', + ); } public function buildOrderSnapshot(OrderChannel $channel, int $totalAmount, array $lineItems, bool $isAffiliate = false): ?array diff --git a/app/Services/System/Setting/SystemService.php b/app/Services/System/Setting/SystemService.php index 28d5733..6756152 100644 --- a/app/Services/System/Setting/SystemService.php +++ b/app/Services/System/Setting/SystemService.php @@ -3,6 +3,8 @@ namespace App\Services\System\Setting; use App\Models\SystemConfiguration; +use App\Services\Concerns\RunsInTransaction; +use App\Services\Concerns\SyncsPhotos; use App\Services\Media\MediaService; use App\Settings\SystemSettings; use App\Support\Media\MediaPresenter; @@ -11,6 +13,8 @@ class SystemService { + use RunsInTransaction, SyncsPhotos; + public function __construct( private readonly MediaService $mediaService, ) {} @@ -39,50 +43,70 @@ public function systemData(): array public function updateSystem(array $validated): void { - $settings = app(SystemSettings::class); - $configuration = SystemConfiguration::instance(); + $this->runInTransaction( + function () use ($validated): void { + $settings = app(SystemSettings::class); + $configuration = SystemConfiguration::instance(); - $settings->app_name = $validated['app_name']; - $settings->about_app = $validated['about_app'] ?? null; - $settings->email = $validated['email'] ?? null; - $settings->phone = $validated['phone'] ?? null; - $settings->address = $validated['address'] ?? null; - $settings->save(); + $settings->app_name = $validated['app_name']; + $settings->about_app = $validated['about_app'] ?? null; + $settings->email = $validated['email'] ?? null; + $settings->phone = $validated['phone'] ?? null; + $settings->address = $validated['address'] ?? null; + $settings->save(); - if (isset($validated['logo_s3_key'])) { - $this->mediaService->replaceSingleS3Key($configuration, $validated['logo_s3_key'], 'logo', 'logo'); - } elseif (isset($validated['logo']) && $validated['logo'] instanceof UploadedFile) { - $this->mediaService->replaceSingleFile($configuration, $validated['logo'], 'logo', 'logo'); - } + $this->syncPhotos( + $configuration, + [ + 'photos' => isset($validated['logo']) ? [$validated['logo']] : null, + 's3_keys' => isset($validated['logo_s3_key']) ? [$validated['logo_s3_key']] : null, + ], + maxPhotos: 1, + required: false, + collection: 'logo', + ); - if (isset($validated['favicon_s3_key'])) { - $this->mediaService->replaceSingleS3Key($configuration, $validated['favicon_s3_key'], 'favicon', 'favicon'); - } elseif (isset($validated['favicon']) && $validated['favicon'] instanceof UploadedFile) { - $this->mediaService->replaceSingleFile($configuration, $validated['favicon'], 'favicon', 'favicon'); - } + $this->syncPhotos( + $configuration, + [ + 'photos' => isset($validated['favicon']) ? [$validated['favicon']] : null, + 's3_keys' => isset($validated['favicon_s3_key']) ? [$validated['favicon_s3_key']] : null, + ], + maxPhotos: 1, + required: false, + collection: 'favicon', + ); - if (isset($validated['login_cover_s3_key'])) { - $this->mediaService->replaceSingleS3Key($configuration, $validated['login_cover_s3_key'], 'login_cover', 'login-cover'); - } elseif (isset($validated['login_cover']) && $validated['login_cover'] instanceof UploadedFile) { - $this->mediaService->replaceSingleFile($configuration, $validated['login_cover'], 'login_cover', 'login-cover'); - } + $this->syncPhotos( + $configuration, + [ + 'photos' => isset($validated['login_cover']) ? [$validated['login_cover']] : null, + 's3_keys' => isset($validated['login_cover_s3_key']) ? [$validated['login_cover_s3_key']] : null, + ], + maxPhotos: 1, + required: false, + collection: 'login_cover', + ); - $errors = []; + $errors = []; - if (! $configuration->hasMedia('logo')) { - $errors['logo'] = 'Logo wajib diisi.'; - } + if (! $configuration->hasMedia('logo')) { + $errors['logo'] = 'Logo wajib diisi.'; + } - if (! $configuration->hasMedia('favicon')) { - $errors['favicon'] = 'Favicon wajib diisi.'; - } + if (! $configuration->hasMedia('favicon')) { + $errors['favicon'] = 'Favicon wajib diisi.'; + } - if (! $configuration->hasMedia('login_cover')) { - $errors['login_cover'] = 'Cover login wajib diisi.'; - } + if (! $configuration->hasMedia('login_cover')) { + $errors['login_cover'] = 'Cover login wajib diisi.'; + } - if ($errors !== []) { - throw ValidationException::withMessages($errors); - } + if ($errors !== []) { + throw ValidationException::withMessages($errors); + } + }, + 'Gagal memperbarui pengaturan sistem', + ); } } diff --git a/resources/js/components/AppSidebar.vue b/resources/js/components/AppSidebar.vue index 8c10968..a95518e 100644 --- a/resources/js/components/AppSidebar.vue +++ b/resources/js/components/AppSidebar.vue @@ -24,7 +24,7 @@ interface MenuItem { title: string; href: string; icon: any; - permission?: string; + permission?: string | string[]; badgeKey?: 'pendingLeaveRequests' | 'pendingEmployeeAdvances' | 'pendingCuttings'; } @@ -82,7 +82,18 @@ const menuGroups: MenuGroup[] = [ label: 'Sistem', items: [ { title: 'Role & Permission', href: admin.system.roles.index.url(), icon: Shield, permission: 'roles.view' }, - { title: 'Pengaturan', href: admin.system.settings.index.url(), icon: Settings2, permission: 'settings.view' }, + { + title: 'Pengaturan', + href: admin.system.settings.index.url(), + icon: Settings2, + permission: [ + 'settings.view_system', + 'settings.view_social_media', + 'settings.view_marketplace', + 'settings.view_hr', + 'settings.view_homepage', + ], + }, { title: 'Log Aktivitas', href: admin.system.activity_logs.index.url(), icon: History, permission: 'activity_logs.view' }, ], }, diff --git a/resources/js/composables/useCan.ts b/resources/js/composables/useCan.ts index 6de4de4..e42573f 100644 --- a/resources/js/composables/useCan.ts +++ b/resources/js/composables/useCan.ts @@ -7,7 +7,10 @@ export function useCan() { const permissions = computed(() => page.props.auth.user?.permissions ?? []); const roles = computed(() => page.props.auth.user?.roles ?? []); - function can(permission: string): boolean { + function can(permission: string | string[]): boolean { + if (Array.isArray(permission)) { + return permission.some((p) => permissions.value.includes(p)); + } return permissions.value.includes(permission); } diff --git a/resources/js/pages/admin/system/setting/Index.vue b/resources/js/pages/admin/system/setting/Index.vue index c0bd2c5..3893a9e 100644 --- a/resources/js/pages/admin/system/setting/Index.vue +++ b/resources/js/pages/admin/system/setting/Index.vue @@ -25,6 +25,11 @@ defineProps<{ hr: HrSettingsData; homepage: HomepageSettingsData; hasPendingMarketplaceVerification: boolean; + canUpdateSystem: boolean; + canUpdateSocialMedia: boolean; + canUpdateMarketplace: boolean; + canUpdateHr: boolean; + canUpdateHomepage: boolean; }>(); const { hasRole } = useCan(); @@ -39,10 +44,10 @@ const activeSection = ref( - - - - - + + + + + diff --git a/resources/js/pages/admin/system/setting/form/HomepageSection.vue b/resources/js/pages/admin/system/setting/form/HomepageSection.vue index e8810e8..31e21dd 100644 --- a/resources/js/pages/admin/system/setting/form/HomepageSection.vue +++ b/resources/js/pages/admin/system/setting/form/HomepageSection.vue @@ -13,6 +13,7 @@ import type { HomepageSettingsData } from '@/types/setting'; const props = defineProps<{ data: HomepageSettingsData; + canUpdate: boolean; }>(); const heroImage = ref( @@ -107,7 +108,7 @@ function submit() { -
+