# Hướng dẫn FE — Import / Export Residents

**Tổng quan**
- Mục tiêu: FE cần hỗ trợ tải file mẫu, upload file Excel để import nhiều resident, và export dữ liệu residents hiện tại ra Excel.

**Endpoints**
- `GET /api/v1/residents/import/template` : Tải file mẫu Excel (`.xlsx`).
  - Auth: Bearer token.
  - Response: Excel file (Vietnamese headers, column width 25, tất cả ô là text).

- `POST /api/v1/residents/import` : Upload file Excel để import.
  - Auth: Bearer token.
  - Content-Type: `multipart/form-data` với field `file` chứa file `.xlsx`.
  - Response codes:
    - `200 OK` — tất cả rows import thành công; body là kết quả thành công (mảng resident tạo ra).
    - `207 Multi-Status` — một số row thành công, một số row lỗi. Body: `{ success: true, data: { successful: [...], failed: [{ row, error }, ...] } }`.
    - `422 Unprocessable Entity` — tất cả rows lỗi; body: `{ success: false, errors: [...] }`.

- `GET /api/v1/residents/export` : Xuất Excel từ dữ liệu residents theo cùng query params với `GET /api/v1/residents`.
  - Auth: Bearer token.
  - Query params: giống `GET /api/v1/residents` (filters, sortField, sortOrder, page, pageSize). Nếu muốn xuất toàn bộ, set `pageSize` lớn (ví dụ `pageSize=10000`).
  - Response: attachment Excel file (`Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`). File dùng tiêu đề tiếng Việt, width 25, và tất cả ô là text; header được highlight.

**Import — chi tiết trường (header mapping)**
- FE có thể dùng file mẫu từ endpoint `GET /api/v1/residents/import/template` để đảm bảo định dạng. Import chấp nhận cả tiêu đề tiếng Việt và English (ví dụ `Họ và tên` hoặc `full_name`).
- Mapping (Tiếng Việt → trường nội bộ):
  - `Họ và tên` → `full_name` (recommended)
  - `Email` → `email`
  - `Số điện thoại` → `phone`
  - `Số CCCD/CMND` → `id_card`
  - `Ngày sinh` → `date_of_birth` (ISO `YYYY-MM-DD` hoặc Excel date cell)
  - `Quốc tịch` → `nationality`
  - `Nghề nghiệp` → `job`
  - `Người liên hệ khẩn cấp` → `emergency_contact_name`
  - `Số điện thoại liên hệ khẩn cấp` → `emergency_contact_phone`
  - `Mối quan hệ với người liên hệ khẩn cấp` → `emergency_contact_relationship`
  - `Trạng thái` → `status` (tuỳ chọn, mặc định `active`)
  - `Ngày vào ở` → `move_in_at` (ISO string)
  - `Mã giường` (hoặc `Mã giường(s)`) → `bed_code` / `bed_codes` (bắt buộc): có thể truyền nhiều mã giường trong một ô.

- Lưu ý về `bed_code(s)`:
  - Hỗ trợ nhiều mã cách nhau bằng `,`, `;`, `|`, `/` hoặc newline.
  - Import sẽ tìm `beds.code` tương ứng. Nếu một hoặc nhiều mã không tồn tại, row đó sẽ fail với lỗi `BED_NOT_FOUND`.

**File format / template**
- File mẫu trả về từ `GET /api/v1/residents/import/template` có:
  - Tiêu đề tiếng Việt như trên.
  - Độ rộng cột `wch = 25`.
  - Tất cả ô được ép kiểu text (để Excel không tự format số/ngày).
- FE nên cung cấp 1 button `Download template` gọi endpoint mẫu để người dùng tải file đúng định dạng.

**Import — ví dụ upload bằng fetch**
```js
const fd = new FormData();
fd.append('file', fileInput.files[0]);
const res = await fetch('/api/v1/residents/import', {
  method: 'POST',
  headers: { Authorization: 'Bearer ' + token },
  body: fd,
});
if (res.status === 207) {
  const json = await res.json();
  // json.data.successful and json.data.failed
} else if (res.status === 200) {
  const json = await res.json();
  // all successful
} else {
  const json = await res.json();
  // handle errors
}
```

**Export — ví dụ download bằng fetch**
```js
const params = new URLSearchParams({ filters: currentFilters, page: '1', pageSize: '10000' });
const res = await fetch(`/api/v1/residents/export?${params.toString()}`, {
  method: 'GET',
  headers: { Authorization: 'Bearer ' + token },
});
const blob = await res.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'residents.xlsx';
a.click();
URL.revokeObjectURL(url);
```

**Response handling & UI suggestions**
- Import:
  - Nếu `207` (partial), show two lists: `successful` (số lượng) và `failed` (danh sách lỗi theo row). FE có thể cho phép user tải file lỗi (export failed rows) hoặc hiển thị từng `row` + `error` để chỉnh sửa.
  - Nếu `422`, show error messages (tập trung vào lỗi validation chung).
- Export:
  - Vì export dùng cùng query params như listing, FE nên gửi chính xác `filters/sort/page/pageSize` tương ứng với view hiện tại.
  - Để export toàn bộ, set `pageSize` lớn hoặc implement server-side export-all (nếu backend hỗ trợ sau này).

**Edge cases & notes**
- Dates: importer chấp nhận Excel date cells; nhưng tốt nhất FE ghi hướng dẫn ở UI yêu cầu `YYYY-MM-DD` hoặc dùng mẫu.
- Case/whitespace: importer sẽ trim và so sánh mã giường case-insensitive; tuy nhiên nên đảm bảo mã giường hợp lệ trên UI.
- Kích thước file: hiện backend xử lý đồng bộ; nếu người dùng upload file rất lớn, UX nên cảnh báo và có thể giới hạn kích thước phía FE.
- Xác thực: mọi endpoint yêu cầu Bearer token.

**Checklist để tích hợp nhanh (FE)**
- [ ] Thêm button `Download template` gọi `GET /api/v1/residents/import/template`.
- [ ] Thêm UI `Upload` nhận file `.xlsx`, gửi `multipart/form-data` đến `POST /api/v1/residents/import`.
- [ ] Xử lý response `200/207/422` và hiển thị kết quả/ lỗi theo `row`.
- [ ] Xuất file hiện tại bằng `GET /api/v1/residents/export` với cùng query params như listing (đảm bảo `pageSize` phù hợp).

---

Nếu bạn muốn mình tạo thêm một component React sample (upload form + error table) hoặc tệp markdown được lưu trong repo, mình có thể tạo sẵn. 