web/docs/history/2026-07-23-login-form-functionality.md

78 lines
3.0 KiB
Markdown

# Login Form Functionality - Session 1
**Tanggal:** 2026-07-23
**Status:** Selesai
## Tujuan
Menambahkan fungsionalitas login pada `web2/app/components/LoginForm.vue` dengan referensi dari `web/app/pages/auth/login.vue`.
## Yang Dikerjakan
### 1. Install `vue-sonner`
- Awalnya install `sonner`, tapi paket tersebut menarik React sebagai dependency dan menyebabkan error `Invalid hook call` / `Cannot read properties of null (reading 'useState')`.
- Solusi: ganti dengan `vue-sonner` (Vue-only fork).
### 2. Update `nuxt.config.ts`
- Tambah `runtimeConfig` untuk `apiBase` dan `googleClientId`.
- Tambah `app.head` untuk title template.
### 3. Buat `app/composables/useGoogleAuth.ts`
- Composable untuk Google Identity Services (GIS) One Tap.
- Load script `https://accounts.google.com/gsi/client` secara dinamis.
- Panggil `POST /auth/google-login` ke backend setelah credential diterima.
- Return `loading`, `error`, dan `signInWithGoogle()`.
### 4. Buat `app/components/ui/sonner/Sonner.vue`
- Wrapper component untuk `vue-sonner`'s `Toaster`.
- Di-render di `app.vue` dengan `<ClientOnly>` (hanya di client, bukan SSR).
### 5. Update `app/app.vue`
- Import dan render `<Toaster />` di dalam `<ClientOnly>`.
### 6. Update `app/components/LoginForm.vue`
- Validasi form dengan Zod (`login` wajib, `password` min 8 karakter).
- Submit handler: `POST /auth/login` via `$fetch`.
- Google login handler: `useGoogleAuth().signInWithGoogle()`.
- Loading state pada tombol Masuk dan tombol Google.
- Error handling: field-level errors + toast notification (success/error).
- Navigasi: `<NuxtLink>` untuk "Daftar", "Lupa kata sandi?", "Ketentuan Layanan", "Kebijakan Privasi".
## File yang Diubah/Dibuat
| File | Aksi |
|------|------|
| `nuxt.config.ts` | Diubah - tambah `runtimeConfig` + `app.head` |
| `app/composables/useGoogleAuth.ts` | Dibuat |
| `app/components/ui/sonner/Sonner.vue` | Dibuat |
| `app/components/ui/sonner/index.ts` | Dibuat (auto) |
| `app/app.vue` | Diubah - tambah `<Toaster />` |
| `app/components/LoginForm.vue` | Diubah - tambah fungsionalitas |
| `package.json` | Diubah - tambah `vue-sonner` |
## Issues yang Dihadapi
### 1. `Cannot read properties of null (reading 'useState')`
- **Penyebab:** `sonner` (multi-framework) menarik React ke dalam project Vue.
- **Solusi:** Ganti dengan `vue-sonner`.
### 2. `Invalid hook call` (React hooks error)
- **Penyebab:** Sisa dependency React dari paket `sonner` masih ada di `node_modules/`.
- **Solusi:** Hapus manual `node_modules/react`, `node_modules/react-dom`, `node_modules/@types/react`.
### 3. Build error `Could not load Toaster.vue`
- **Penyebab:** File di direktori `sonner/` bernama `Sonner.vue` tapi import di `app.vue` mencari `Toaster.vue`.
- **Solusi:** Update import path di `app.vue` ke `Sonner.vue`.
## API yang Digunakan
- `POST /v1/auth/login` - Body: `{ login, password }`
- `POST /v1/auth/google-login` - Body: `{ credential }` (Google JWT)
## Environment Variables
```
NUXT_PUBLIC_API_BASE=http://localhost:8000/v1
NUXT_PUBLIC_GOOGLE_CLIENT_ID=
```