78 lines
3.0 KiB
Markdown
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=
|
|
```
|