# CRUD Business Type dengan Dialog Modal

**Tanggal:** 2026-07-24
**Status:** Selesai

## Tujuan
Membangun fitur CRUD lengkap untuk Jenis Bisnis (Business Type) menggunakan dialog modal shadcn-vue, termasuk toggle status inline, dan endpoint API terpisah untuk toggle status.

## Yang Dikerjakan

### 1. CRUD dengan Dialog Modal
- Membuat form dialog gabungan untuk Create dan Edit (1 dialog, 2 mode)
- Membuat komponen `DeleteDialog` reusable untuk konfirmasi hapus
- Form fields: Kode (input), Nama (input), Deskripsi (textarea)
- Field Status dihapus dari form edit, diganti dengan toggle inline di tabel

### 2. Toggle Status Inline
- Menambahkan komponen `Switch` di samping Badge status pada tabel
- Klik toggle langsung memanggil endpoint PATCH tanpa buka modal
- Optimistic update pada data lokal tanpa refresh seluruh tabel (menggunakan `.map()` untuk trigger reactivity)

### 3. Switch Component
- Install komponen `switch` dari shadcn-vue
- Menggunakan `modelValue`/`@update:modelValue` (bukan `checked`) karena reka-ui SwitchRoot

### 4. Sonner Toast
- Menambahkan import CSS `vue-sonner/style.css` di `tailwind.css` agar toast muncul

### 5. Endpoint API Toggle Status
- Menambahkan schema `BusinessTypeToggleStatus` (hanya field `is_active: bool`)
- Menambahkan service `toggle_business_type_status()`
- Menambahkan endpoint `PATCH /v1/business-types/{id}/active`
- Frontend diupdate dari `PUT` ke `PATCH .../active`

### 6. columns.ts Refactor
- Export diubah dari konstanta ke fungsi `getColumns(callbacks)` yang menerima `onEdit`, `onDelete`, `onToggleStatus`
- Tombol aksi (Pencil, Trash2) sekarang memanggil callback dengan data row

## File yang Diubah

| File | Aksi | Detail |
|------|------|--------|
| `web2/app/pages/admin/business-types/columns.ts` | Diubah | Export ke fungsi `getColumns()`, tambah Switch di status column, tambah callback `onToggleStatus` |
| `web2/app/pages/admin/business-types/index.vue` | Diubah | CRUD dialog (create/edit gabung), toggle status inline, hapus field status dari form edit |
| `web2/app/components/DeleteDialog.vue` | Dibuat | Komponen reusable delete confirmation dialog |
| `web2/app/components/ui/switch/Switch.vue` | Dibuat | Komponen switch dari shadcn-vue |
| `web2/app/components/ui/switch/index.ts` | Dibuat | Export switch component |
| `web2/app/assets/css/tailwind.css` | Diubah | Tambah `@import "vue-sonner/style.css"` |
| `api/app/schemas/business_type.py` | Diubah | Tambah `BusinessTypeToggleStatus` schema |
| `api/app/services/business_type_service.py` | Diubah | Tambah `toggle_business_type_status()` function |
| `api/app/routers/business_types.py` | Diubah | Tambah `PATCH /{id}/active` endpoint |

## API Endpoints

| Method | Endpoint | Fungsi |
|--------|----------|--------|
| `GET` | `/v1/business-types/` | List (opsional `?is_active=`) |
| `GET` | `/v1/business-types/{id}` | Get by ID |
| `POST` | `/v1/business-types/` | Create |
| `PUT` | `/v1/business-types/{id}` | Update (code, name, description) |
| `PATCH` | `/v1/business-types/{id}/active` | Toggle status (is_active) |
| `DELETE` | `/v1/business-types/{id}` | Soft delete |

## Notes
- `DeleteDialog` dipindah dari `components/dialog/DeleteDialog.vue` ke `components/DeleteDialog.vue` karena Nuxt auto-import dari root `components/`
- Switch reka-ui menggunakan `modelValue` bukan `checked` saat di-render via `h()` function
- Toggle status menggunakan optimistic update (`.map()` + spread) supaya switch langsung bergerak tanpa re-render tabel
