From 432bbd110abaefdfa69437ee918a48457816079e Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Wed, 10 Jun 2026 02:06:14 +0700 Subject: [PATCH] Add category management routes, permissions, and UI components. Integrate new permissions for categories in the Permission and Role enums, and update the sidebar to include category navigation. Enhance the composer configuration by adding the Spatie Laravel Sluggable package for slug generation. --- app/Enums/Permission.php | 12 ++ app/Enums/Role.php | 13 ++ .../Controllers/Admin/CategoryController.php | 97 +++++++++++++++ app/Http/Requests/Admin/CategoryRequest.php | 28 +++++ app/Models/Category.php | 15 +++ composer.json | 3 +- composer.lock | 80 +++++++++++- ...6_06_09_185347_create_categories_table.php | 24 ++++ resources/js/components/AppSidebar.vue | 18 ++- .../categories/CategoryFormModal.vue | 116 ++++++++++++++++++ resources/js/components/categories/columns.ts | 24 ++++ resources/js/pages/admin/categories/Index.vue | 108 ++++++++++++++++ resources/js/types/category.ts | 29 +++++ routes/web.php | 78 ++++++++---- 14 files changed, 620 insertions(+), 25 deletions(-) create mode 100644 app/Http/Controllers/Admin/CategoryController.php create mode 100644 app/Http/Requests/Admin/CategoryRequest.php create mode 100644 app/Models/Category.php create mode 100644 database/migrations/2026_06_09_185347_create_categories_table.php create mode 100644 resources/js/components/categories/CategoryFormModal.vue create mode 100644 resources/js/components/categories/columns.ts create mode 100644 resources/js/pages/admin/categories/Index.vue create mode 100644 resources/js/types/category.ts diff --git a/app/Enums/Permission.php b/app/Enums/Permission.php index babf5db..c8a14ef 100644 --- a/app/Enums/Permission.php +++ b/app/Enums/Permission.php @@ -17,6 +17,11 @@ enum Permission: string case EMPLOYEES_RESET_PASSWORD = 'employees.reset-password'; case EMPLOYEES_TOGGLE_STATUS = 'employees.toggle-status'; + case CATEGORIES_VIEW = 'categories.view'; + case CATEGORIES_CREATE = 'categories.create'; + case CATEGORIES_UPDATE = 'categories.update'; + case CATEGORIES_DELETE = 'categories.delete'; + public function label(): string { return match ($this) { @@ -28,6 +33,11 @@ public function label(): string self::EMPLOYEES_DELETE => 'Hapus Pegawai', self::EMPLOYEES_RESET_PASSWORD => 'Reset Kata Sandi Pegawai', self::EMPLOYEES_TOGGLE_STATUS => 'Ubah Status Pegawai', + + self::CATEGORIES_VIEW => 'Lihat Kategori', + self::CATEGORIES_CREATE => 'Tambah Kategori', + self::CATEGORIES_UPDATE => 'Ubah Kategori', + self::CATEGORIES_DELETE => 'Hapus Kategori', }; } @@ -37,6 +47,8 @@ public function group(): string self::DASHBOARD_VIEW => 'Umum', self::EMPLOYEES_VIEW, self::EMPLOYEES_CREATE, self::EMPLOYEES_UPDATE, self::EMPLOYEES_DELETE, self::EMPLOYEES_RESET_PASSWORD, self::EMPLOYEES_TOGGLE_STATUS => 'Pegawai', + self::CATEGORIES_VIEW, self::CATEGORIES_CREATE, self::CATEGORIES_UPDATE, + self::CATEGORIES_DELETE => 'Kategori', }; } diff --git a/app/Enums/Role.php b/app/Enums/Role.php index dbdc287..2ef08ab 100644 --- a/app/Enums/Role.php +++ b/app/Enums/Role.php @@ -44,6 +44,10 @@ public function permissions(): array Permission::EMPLOYEES_DELETE, Permission::EMPLOYEES_RESET_PASSWORD, Permission::EMPLOYEES_TOGGLE_STATUS, + Permission::CATEGORIES_VIEW, + Permission::CATEGORIES_CREATE, + Permission::CATEGORIES_UPDATE, + Permission::CATEGORIES_DELETE, ], self::ADMIN_TOKO => [ Permission::DASHBOARD_VIEW, @@ -52,14 +56,23 @@ public function permissions(): array Permission::EMPLOYEES_UPDATE, Permission::EMPLOYEES_RESET_PASSWORD, Permission::EMPLOYEES_TOGGLE_STATUS, + Permission::CATEGORIES_VIEW, + Permission::CATEGORIES_CREATE, + Permission::CATEGORIES_UPDATE, + Permission::CATEGORIES_DELETE, ], self::ADMIN_BAHAN_BAKU => [ Permission::DASHBOARD_VIEW, Permission::EMPLOYEES_VIEW, + Permission::CATEGORIES_VIEW, + Permission::CATEGORIES_CREATE, + Permission::CATEGORIES_UPDATE, + Permission::CATEGORIES_DELETE, ], self::MARKETING => [ Permission::DASHBOARD_VIEW, Permission::EMPLOYEES_VIEW, + Permission::CATEGORIES_VIEW, ], self::NON_OPERATOR => [ Permission::DASHBOARD_VIEW, diff --git a/app/Http/Controllers/Admin/CategoryController.php b/app/Http/Controllers/Admin/CategoryController.php new file mode 100644 index 0000000..2dc29d4 --- /dev/null +++ b/app/Http/Controllers/Admin/CategoryController.php @@ -0,0 +1,97 @@ +parseDataTableQuery($request); + $search = $tableQuery['search']; + $sort = $tableQuery['sort']; + $direction = $tableQuery['direction']; + + $query = Category::query() + ->when($search !== '', function (Builder $query) use ($search): void { + $query->where(function (Builder $query) use ($search): void { + $query->where('name', 'like', "%{$search}%"); + }); + }); + + $this->applySorting($query, $sort, $direction); + + $categories = $query + ->paginate(10) + ->withQueryString() + ->through(fn (Category $category) => $this->transformCategory($category)); + + return Inertia::render('admin/categories/Index', [ + 'categories' => $categories, + 'filters' => $this->dataTableFilters($tableQuery), + ]); + } + + public function store(CategoryRequest $request): RedirectResponse + { + Category::create($request->validated()); + + Inertia::flash('success', 'Kategori berhasil ditambahkan.'); + + return redirect()->route('admin.master.categories.index'); + } + + public function update(CategoryRequest $request, Category $category): RedirectResponse + { + $validated = $request->validated(); + $category->name = $validated['name']; + $category->save(); + + Inertia::flash('success', 'Kategori berhasil diperbarui.'); + + return redirect()->route('admin.master.categories.index'); + } + + public function destroy(Category $category): RedirectResponse + { + $category->delete(); + + Inertia::flash('success', 'Kategori berhasil dihapus.'); + + return redirect()->route('admin.master.categories.index'); + } + + private function applySorting(Builder $query, string $sort, string $direction): void + { + if (in_array($sort, ['name', 'slug'], true)) { + $query->orderBy($sort, $direction); + + return; + } + + $query->latest(); + } + + /** + * @return array + */ + private function transformCategory(Category $category): array + { + return [ + 'id' => $category->id, + 'name' => $category->name, + 'slug' => $category->slug, + ]; + } +} diff --git a/app/Http/Requests/Admin/CategoryRequest.php b/app/Http/Requests/Admin/CategoryRequest.php new file mode 100644 index 0000000..cc3f55c --- /dev/null +++ b/app/Http/Requests/Admin/CategoryRequest.php @@ -0,0 +1,28 @@ +isMethod('POST') + ? Permission::CATEGORIES_CREATE + : Permission::CATEGORIES_UPDATE; + + return $this->user()?->can($permission->value) ?? false; + } + + /** + * @return array + */ + public function rules(): array + { + return [ + 'name' => ['required', 'string', 'max:50'], + ]; + } +} diff --git a/app/Models/Category.php b/app/Models/Category.php new file mode 100644 index 0000000..3e6bba4 --- /dev/null +++ b/app/Models/Category.php @@ -0,0 +1,15 @@ +id(); + $table->string('name', 50); + $table->string('slug', 50)->unique(); + $table->timestamps(); + $table->softDeletes(); + }); + } + + public function down(): void + { + Schema::dropIfExists('categories'); + } +}; diff --git a/resources/js/components/AppSidebar.vue b/resources/js/components/AppSidebar.vue index 01093dc..cee0667 100644 --- a/resources/js/components/AppSidebar.vue +++ b/resources/js/components/AppSidebar.vue @@ -1,6 +1,6 @@