feat: refactor controllers and update department service usage for consistency
Some checks failed
tests / ci (pull_request) Has been cancelled
Some checks failed
tests / ci (pull_request) Has been cancelled
This commit is contained in:
parent
5901f8e649
commit
e6f272bb59
@ -15,7 +15,9 @@
|
||||
|
||||
class FeedbackController extends Controller
|
||||
{
|
||||
public function __construct(private readonly FeedbackService $service) {}
|
||||
public function __construct(
|
||||
private readonly FeedbackService $service,
|
||||
) {}
|
||||
|
||||
public function index(PaginatedRequest $request): Response
|
||||
{
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
use App\Http\Requests\PaginatedRequest;
|
||||
use App\Models\Course;
|
||||
use App\Services\Admin\Manage\CourseService;
|
||||
use App\Services\Admin\Users\DepartmentService;
|
||||
use App\Services\Admin\Master\DepartmentService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Inertia\Inertia;
|
||||
use Inertia\Response;
|
||||
|
||||
@ -49,8 +49,6 @@ public function destroy(Material $material): RedirectResponse
|
||||
{
|
||||
$this->service->delete($material);
|
||||
|
||||
Inertia::flash('toast', ['type' => 'success', 'message' => 'Materi berhasil dihapus.']);
|
||||
|
||||
return back();
|
||||
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Materi berhasil dihapus.'])->back();
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,8 +48,6 @@ public function destroy(Schedule $schedule): RedirectResponse
|
||||
{
|
||||
$this->service->delete($schedule);
|
||||
|
||||
Inertia::flash('toast', ['type' => 'success', 'message' => 'Jadwal berhasil dihapus.']);
|
||||
|
||||
return back();
|
||||
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Jadwal berhasil dihapus.'])->back();
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,8 +52,6 @@ public function destroy(TuitionInvoice $tuitionInvoice): RedirectResponse
|
||||
{
|
||||
$this->service->delete($tuitionInvoice);
|
||||
|
||||
Inertia::flash('toast', ['type' => 'success', 'message' => 'Tagihan berhasil dihapus.']);
|
||||
|
||||
return back();
|
||||
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Tagihan berhasil dihapus.'])->back();
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
class AcademicTermController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AcademicTermService $service
|
||||
private readonly AcademicTermService $service,
|
||||
) {}
|
||||
|
||||
public function index(PaginatedRequest $request): Response
|
||||
@ -33,18 +33,18 @@ public function store(AcademicTermRequest $request): RedirectResponse
|
||||
return to_route('admin.master.academic-terms.index');
|
||||
}
|
||||
|
||||
public function update(AcademicTermRequest $request, AcademicTerm $AcademicTerm): RedirectResponse
|
||||
public function update(AcademicTermRequest $request, AcademicTerm $academicTerm): RedirectResponse
|
||||
{
|
||||
$this->service->update($AcademicTerm, $request->validated());
|
||||
$this->service->update($academicTerm, $request->validated());
|
||||
|
||||
Inertia::flash('toast', ['type' => 'success', 'message' => 'Periode akademik berhasil diperbarui.']);
|
||||
|
||||
return to_route('admin.master.academic-terms.index');
|
||||
}
|
||||
|
||||
public function destroy(AcademicTerm $AcademicTerm): RedirectResponse
|
||||
public function destroy(AcademicTerm $academicTerm): RedirectResponse
|
||||
{
|
||||
$this->service->delete($AcademicTerm);
|
||||
$this->service->delete($academicTerm);
|
||||
|
||||
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Periode akademik berhasil dihapus.'])->back();
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
class DepartmentController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DepartmentService $service
|
||||
private readonly DepartmentService $service,
|
||||
) {}
|
||||
|
||||
public function index(PaginatedRequest $request): Response
|
||||
|
||||
@ -15,9 +15,6 @@
|
||||
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show the user's profile settings page.
|
||||
*/
|
||||
public function edit(Request $request): Response
|
||||
{
|
||||
$user = $request->user();
|
||||
@ -37,9 +34,6 @@ public function edit(Request $request): Response
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user's profile information.
|
||||
*/
|
||||
public function update(ProfileUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
@ -61,9 +55,6 @@ public function update(ProfileUpdateRequest $request): RedirectResponse
|
||||
return to_route('admin.settings.profile.edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the user's profile.
|
||||
*/
|
||||
public function destroy(ProfileDeleteRequest $request): RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
@ -11,9 +11,6 @@
|
||||
|
||||
class SecurityController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show the user's security settings page.
|
||||
*/
|
||||
public function edit(): Response
|
||||
{
|
||||
return Inertia::render('admin/settings/security', [
|
||||
@ -21,17 +18,12 @@ public function edit(): Response
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the user's password.
|
||||
*/
|
||||
public function update(PasswordUpdateRequest $request): RedirectResponse
|
||||
{
|
||||
$request->user()->update([
|
||||
'password' => $request->password,
|
||||
]);
|
||||
|
||||
Inertia::flash('toast', ['type' => 'success', 'message' => 'Kata sandi berhasil diperbarui.']);
|
||||
|
||||
return back();
|
||||
return Inertia::flash('toast', ['type' => 'success', 'message' => 'Kata sandi berhasil diperbarui.'])->back();
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
class AdministratorController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
protected AdministratorService $service,
|
||||
private readonly AdministratorService $service,
|
||||
) {}
|
||||
|
||||
public function index(Request $request): Response
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\Users\LecturerRequest;
|
||||
use App\Models\User;
|
||||
use App\Services\Admin\Users\DepartmentService;
|
||||
use App\Services\Admin\Master\DepartmentService;
|
||||
use App\Services\Admin\Users\LecturerService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@ -15,8 +15,8 @@
|
||||
class LecturerController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
protected LecturerService $service,
|
||||
protected DepartmentService $departmentService,
|
||||
private readonly LecturerService $service,
|
||||
private readonly DepartmentService $departmentService,
|
||||
) {}
|
||||
|
||||
public function index(Request $request): Response
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\Admin\Users\StudentRequest;
|
||||
use App\Models\User;
|
||||
use App\Services\Admin\Users\DepartmentService;
|
||||
use App\Services\Admin\Master\DepartmentService;
|
||||
use App\Services\Admin\Users\LecturerService;
|
||||
use App\Services\Admin\Users\StudentService;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
@ -16,9 +16,9 @@
|
||||
class StudentController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
protected StudentService $service,
|
||||
protected DepartmentService $departmentService,
|
||||
protected LecturerService $lecturerService,
|
||||
private readonly StudentService $service,
|
||||
private readonly DepartmentService $departmentService,
|
||||
private readonly LecturerService $lecturerService,
|
||||
) {}
|
||||
|
||||
public function index(Request $request): Response
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Admin\Users;
|
||||
|
||||
use App\Models\Department;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class DepartmentService
|
||||
{
|
||||
public function getAll(): Collection
|
||||
{
|
||||
return Department::select(['id', 'name'])->get();
|
||||
}
|
||||
}
|
||||
155
docs/code-style.md
Normal file
155
docs/code-style.md
Normal file
@ -0,0 +1,155 @@
|
||||
# Panduan Gaya Kode
|
||||
|
||||
Dokumen ini mencatat konvensi penulisan kode di proyek ini, supaya kontributor
|
||||
(termasuk AI assistant) mengikuti pola yang sama dan tidak menulis ulang
|
||||
solusi yang sudah ada dengan cara berbeda-beda di tiap file.
|
||||
|
||||
Setiap bagian punya status:
|
||||
|
||||
- ✅ **Selesai** — sudah diterapkan di seluruh kode yang relevan.
|
||||
- 🚧 **Sebagian** — sudah ada polanya, tapi belum diterapkan di semua tempat.
|
||||
- 📝 **Rencana** — baru berupa kesepakatan, belum diterapkan.
|
||||
|
||||
---
|
||||
|
||||
## 1. Enum ✅
|
||||
|
||||
**Aturan:** setiap backed enum (`enum X: string`) wajib pakai trait
|
||||
`App\Enums\Concerns\HasValues`. Jangan pernah menulis
|
||||
`array_values(X::cases())` atau `array_column(X::cases(), 'value')` secara
|
||||
manual — pakai `X::values()` (atau `X::options()` kalau butuh label untuk
|
||||
dropdown/select).
|
||||
|
||||
```php
|
||||
// app/Enums/Concerns/HasValues.php
|
||||
trait HasValues
|
||||
{
|
||||
public static function values(): array // ['male', 'female']
|
||||
public static function options(): array // [{value: 'male', label: 'Laki-laki'}, ...]
|
||||
}
|
||||
```
|
||||
|
||||
Struktur enum standar:
|
||||
|
||||
```php
|
||||
enum Gender: string
|
||||
{
|
||||
use HasValues;
|
||||
|
||||
case Male = 'male';
|
||||
case Female = 'female';
|
||||
|
||||
public function label(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Male => 'Laki-laki',
|
||||
self::Female => 'Perempuan',
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Sebelum → Sesudah**
|
||||
|
||||
```php
|
||||
// ❌ Jangan
|
||||
'gender' => ['required', 'string', Rule::in(array_values(Gender::cases()))],
|
||||
'type' => ['required', 'string', Rule::in(array_column(FeedbackType::cases(), 'value'))],
|
||||
|
||||
// ✅ Pakai
|
||||
'gender' => ['required', 'string', Rule::in(Gender::values())],
|
||||
'type' => ['required', 'string', Rule::in(FeedbackType::values())],
|
||||
```
|
||||
|
||||
Untuk data yang dikirim ke frontend (mis. isi `<Select>`), pakai `options()`
|
||||
alih-alih membangun array `{value, label}` manual dengan `array_map`:
|
||||
|
||||
```php
|
||||
// ❌ Jangan
|
||||
'types' => array_map(fn (FeedbackType $type) => [
|
||||
'value' => $type->value,
|
||||
'label' => $type->label(),
|
||||
], FeedbackType::cases()),
|
||||
|
||||
// ✅ Pakai
|
||||
'types' => FeedbackType::options(),
|
||||
```
|
||||
|
||||
Enum baru **wajib** langsung pakai `use HasValues;` sejak awal dibuat, tidak
|
||||
perlu menunggu ada kebutuhan `values()`/`options()` baru ditambahkan.
|
||||
|
||||
---
|
||||
|
||||
## 2. Migration ✅
|
||||
|
||||
**Aturan:** kolom `enum()` di migration wajib pakai `EnumClass::values()`,
|
||||
konsisten dengan aturan Enum di atas. Kolom `->default()` wajib pakai
|
||||
`EnumClass::Case->value` (string), bukan objek case-nya langsung.
|
||||
|
||||
```php
|
||||
// ❌ Jangan
|
||||
$table->enum('status', array_values(StudentStatus::cases()))
|
||||
->nullable()
|
||||
->default(StudentStatus::Active); // objek enum, bukan string
|
||||
|
||||
// ✅ Pakai
|
||||
$table->enum('status', StudentStatus::values())
|
||||
->nullable()
|
||||
->default(StudentStatus::Active->value);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Bahasa UI ✅
|
||||
|
||||
Seluruh teks yang tampil ke pengguna (label, judul halaman, pesan toast,
|
||||
placeholder, pesan error) ditulis dalam **Bahasa Indonesia**. Istilah teknis
|
||||
dan identifier kode tetap dalam bahasa aslinya (bahasa Inggris), tapi teks
|
||||
yang dibaca pengguna — termasuk teks di halaman auth/settings bawaan
|
||||
starter-kit yang aslinya berbahasa Inggris — harus diterjemahkan supaya
|
||||
konsisten dengan sisa aplikasi.
|
||||
|
||||
---
|
||||
|
||||
## 4. Struktur modul Admin ✅
|
||||
|
||||
Semua fitur berada di bawah `/admin` — tidak ada lagi controller atau
|
||||
halaman yang menggantung di top-level `App\Http\Controllers` /
|
||||
`resources/js/pages/` di luar folder `admin/`. Setiap fitur admin baru
|
||||
(CRUD) mengikuti struktur namespace yang sama, di salah satu dari lima grup:
|
||||
|
||||
| Grup | Namespace Controller/Request | Prefix route |
|
||||
| ------------------ | --------------------------------------- | ------------------ |
|
||||
| Master data | `Admin\Master` | `admin/master/*` |
|
||||
| Data operasional | `Admin\Manage` | `admin/manage/*` |
|
||||
| Manajemen pengguna | `Admin\Users` | `admin/users/*` |
|
||||
| Pengaturan akun | `Admin\Settings` | `admin/settings/*` |
|
||||
| Resource mandiri | `Admin` (langsung, tanpa sub-namespace) | `admin/<resource>` |
|
||||
|
||||
"Resource mandiri" dipakai untuk fitur yang tidak cocok masuk ke 4 grup di
|
||||
atas — misalnya `Admin\FeedbackController` di `admin/feedback` (data
|
||||
personal milik user yang sedang login, bukan data akademik yang dikelola
|
||||
admin atas user lain).
|
||||
|
||||
Nama route mengikuti pola `admin.<grup>.<resource>.<action>` (atau
|
||||
`admin.<resource>.<action>` untuk resource mandiri), dan file Wayfinder
|
||||
hasil generate mengikuti struktur folder yang sama di
|
||||
`resources/js/routes/admin/<grup>/<resource>/`.
|
||||
|
||||
Halaman CRUD frontend memakai pola: `PageHeader` (judul + tombol Tambah) →
|
||||
`FormDialog` (Create/Edit) → `DataTable` + `columns.tsx` → `DeleteConfirmDialog`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Wayfinder ✅
|
||||
|
||||
Selalu jalankan generate dengan flag form variant, supaya `<Form
|
||||
{...Controller.method.form()}>` tidak error saat runtime:
|
||||
|
||||
```bash
|
||||
php artisan wayfinder:generate --with-form
|
||||
```
|
||||
|
||||
`vite.config.ts` sudah diset `wayfinder({ formVariants: true })` sehingga
|
||||
dev-server otomatis benar. Flag `--with-form` hanya wajib diingat kalau
|
||||
generate manual lewat CLI.
|
||||
Loading…
Reference in New Issue
Block a user