# Perbaikan Form User dan Filter Status

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

## Tujuan
- Validasi form menggunakan pesan dari server (422 validation)
- Filter status tabel menggunakan API query param
- PhoneInput component reusable dengan format otomatis
- Kalender popover untuk input tanggal lahir
- Layout form diseragamkan antara create dan edit

## Yang Dikerjakan

### 1. Validasi Form dari Server
- `errors` diubah dari `Record<string, boolean>` menjadi `Record<string, string>` untuk menyimpan pesan error
- Template menggunakan `{{ errors.email }}` dinamis, bukan hardcode
- Catch block parsing response 422 FastAPI: `err.loc.at(-1)` sebagai field name, `err.msg` sebagai pesan
- Untuk response error lain, tetap parsing `detail.message` dan map ke field berdasarkan keyword

### 2. Filter Status via API
- Sebelum: filter status client-side (DataTable column filter)
- Sesudah: `statusFilter` reactive ref dikirim sebagai query param `?status=` ke endpoint API
- `useFetch` dengan `watch: [statusFilter]` otomatis refetch saat filter berubah
- Opsi filter: Semua Status, Aktif, Onboarding, Nonaktif, Ditangguhkan, Dinonaktifkan

### 3. PhoneInput Component
- Dibuat `components/ui/phone-input/PhoneInput.vue`
- Format otomatis `xxxx xxxx xxxx` (13 digit, spasi tiap 4 digit)
- Menggunakan native `<input>` dengan `:value` + `@input` untuk menghindari konflik v-model shadcn
- Menerima prop `class` untuk validasi red border
- Digunakan di create.vue dan edit.vue, nomor dikirim tanpa spasi ke API

### 4. Kalender Popover untuk Tanggal Lahir
- Input `type="date"` diganti dengan Popover + Calendar component
- `dob` dipisah dari form object, menggunakan `ref<CalendarDate>()`
- Format tampilan: "25 Juli 2026" (locale id-ID)
- Konversi `CalendarDate.toString()` → YYYY-MM-DD untuk dikirim ke API
- Parsing string YYYY-MM-DD → `new CalendarDate(y, m, d)` saat load edit

### 5. Layout Form Diseragamkan
- Edit page sekarang mengikuti layout create page:
  - Baris 1: email + username (2 kolom)
  - Baris 2: full_name (1 baris penuh)
  - Baris 3: phone + pob + dob (3 kolom)
  - Baris 4: alamat (1 baris penuh)
- Info alert password default ditambahkan ke edit page

### 6. Badge Status User
- Badge sekarang menggunakan `statusConfig` untuk 5 status:
  - ACTIVE → hijau "Aktif"
  - ONBOARDING → biru "Onboarding"
  - INACTIVE → abu "Nonaktif"
  - SUSPENDED → oranye "Ditangguhkan"
  - DISABLED → merah "Dinonaktifkan"

## File yang Diubah

| File | Aksi | Detail |
|------|------|--------|
| `components/ui/phone-input/PhoneInput.vue` | Dibuat | Component input telepon dengan format otomatis |
| `components/ui/phone-input/index.ts` | Dibuat | Export PhoneInput |
| `pages/admin/users/create.vue` | Diubah | Calendar popover, PhoneInput, validasi dinamis, status dihapus dari body |
| `pages/admin/users/[id]/edit.vue` | Diubah | Layout disamakan dengan create, Calendar popover, PhoneInput, validasi dinamis, info alert |
| `pages/admin/users/index.vue` | Diubah | Filter status via API query param, 5 opsi status |
| `pages/admin/users/columns.ts` | Diubah | statusConfig untuk badge 5 status, hapus statusFilter |

## Notes
- Create page tidak lagi mengirim `status` ke API (default ONBOARDING dari schema)
- Phone component hanya menerima input digit, max 13 digit
