# Modal "Chọn người dùng/nhóm người dùng" (org-chart picker)

> Tài liệu con của [`KHO-TAI-LIEU.md`](./KHO-TAI-LIEU.md).
> Khảo sát trực tiếp bằng Playwright MCP ngày **2026-07-27** trên sitdev, tài khoản `ecm01`.
> Modal này **dùng chung** cho mọi people-picker có nút org-chart, nên nhiều màn khác cũng áp dụng được.

> 📌 **Phạm vi tài liệu — chỉ mô tả màn hình** (field, nút, testId, cấu trúc modal, thông báo, luồng
> thao tác). **Không** ghi logic test / kỳ vọng của case / quy tắc nghiệp vụ vào đây — chỗ của chúng
> là spec `tests/<mục>/`, `<mục>.steps.ts` và `<mục>.md`. Xem `KHO-TAI-LIEU.md` mục đầu file.

---

## 1. Cách mở

Bấm nút org-chart nằm bên phải mỗi people-picker:

```ts
await page.getByTestId("pp-multi-usersRightViewers-orgchart-btn").click();
await page.waitForTimeout(6000);
```

Quy ước testId: `<testId của people-picker>-orgchart-btn`.
Đã xác minh có trên: `pp-multi-usersRightOwner`, `pp-multi-usersRightAdd`, `pp-multi-usersRightEdit`,
`pp-multi-usersRightDownload`, `pp-multi-usersRightViewers` (form BHS) và `pp-multi-signatory`
(modal Thêm thư mục).

Tiêu đề modal: text `"Chọn người dùng/nhóm người dùng"`
(⚠️ modal này **không** có `lbl-modal-title`).

---

## 2. Element trong modal

| Element                        | testId                             | Ghi chú                                                    |
| ------------------------------ | ---------------------------------- | ------------------------------------------------------------ |
| Nút đóng                       | `btn-dong-nguoi-dung`              | Icon X                                                       |
| Ô tìm đơn vị                   | `txt-tim-don-vi`                   | Placeholder `Nhập tên đơn vị`                                |
| Cây **Cơ cấu tổ chức**         | `Tree-sel-co-cau-to-chuc`          | ⚠️ testId viết hoa chữ `T` — không đúng quy ước dự án        |
| Từng node trong cây            | `Tree-sel-item`                    | ⚠️ **nhiều element cùng testId** → dùng `.filter({ hasText })` |
| Phạm vi: **Đơn vị đang chọn**  | `chk-pham-vi-don-vi-dang-chon`     | checkbox                                                     |
| Phạm vi: **Nhóm người dùng**   | `chk-pham-vi-nhom-nguoi-dung`      | checkbox                                                     |
| Ô tìm người dùng               | `txt-tim-nguoi-dung`               | Placeholder `Nhập tên, email người dùng/ nhóm người dùng`    |
| Bảng danh sách người dùng      | `tbl-danh-sach-nguoi-dung`         | Cột: `""`, `Tên`, `Email`, `Đơn vị`, `""`                    |
| Nút **Thêm**                   | `btn-them-nguoi-dung`              | Xác nhận chọn                                                |

### Mỗi dòng người dùng

| Element              | testId                    | Ghi chú                                   |
| -------------------- | ------------------------- | ------------------------------------------- |
| Dòng                 | `row-nguoi-dung`          | ⚠️ **nhiều dòng cùng testId** → filter theo text |
| Checkbox chọn        | `chk-chon-nguoi-dung`     | ⚠️ cùng testId ở mọi dòng → scope trong dòng |
| Tên hiển thị         | `lbl-ten-nguoi-dung`      | Bên trong có `avatar-fullname`, `avatar-subtitle` (chức danh) |
| Email                | `lbl-email-nguoi-dung`    | Có thể rỗng                                 |
| Đơn vị               | `lbl-don-vi-nguoi-dung`   | —                                           |

---

## 3. Pattern chọn 1 người

```ts
const modal = page.locator(".ant-modal-content:visible").last();

// Tìm theo tên/email:
await modal.getByTestId("txt-tim-nguoi-dung").fill("ecm05");
await page.waitForTimeout(TIMEOUT.DATA_LOADING);

// Tick dòng khớp:
const row = modal.getByTestId("row-nguoi-dung").filter({ hasText: "Đỗ Mạnh Cường" }).first();
await row.getByTestId("chk-chon-nguoi-dung").click();

await modal.getByTestId("btn-them-nguoi-dung").click();
```

## 4. Pattern chọn theo đơn vị (cây cơ cấu tổ chức)

```ts
await modal.getByTestId("txt-tim-don-vi").fill("Ban Tài chính");
await page.waitForTimeout(TIMEOUT.DATA_LOADING);
await modal.getByTestId("Tree-sel-item").filter({ hasText: "Ban Tài chính" }).first().click();
await page.waitForTimeout(TIMEOUT.DATA_LOADING);
// bảng người dùng bên phải lọc lại theo đơn vị vừa chọn
```

---

## 5. Hành vi đã kiểm chứng (2026-07-27)

### 5a. Nút "Thêm" (`btn-them-nguoi-dung`)

Sau khi tick `chk-chon-nguoi-dung` của 1 dòng rồi bấm `btn-them-nguoi-dung`:

- Modal **tự đóng** (số modal trở về như trước khi mở)
- Chip được thêm đúng vào people-picker gốc (`.ant-tag` +1)
- **Không có toast**

```ts
await om.getByTestId("row-nguoi-dung").filter({ hasText: "Lê Duy Nam" }).first()
  .getByTestId("chk-chon-nguoi-dung").click();
await om.getByTestId("btn-them-nguoi-dung").click();
await expect(
  page.getByTestId("pp-multi-usersRightAdd").locator(".ant-tag"),
).toHaveCount(1);
```

### 5b. Checkbox "Phạm vi"

| Checkbox                        | Tác dụng                                                                   |
| ------------------------------- | ---------------------------------------------------------------------------- |
| `chk-pham-vi-nhom-nguoi-dung`   | Bảng bên phải chuyển sang liệt kê **nhóm người dùng** (vd `sysadmins`)      |
| `chk-pham-vi-don-vi-dang-chon`  | Giới hạn danh sách theo **đơn vị đang chọn** trong cây cơ cấu tổ chức       |

Cả 2 là `input[type=checkbox]` ẩn của AntD → click bằng `{ force: true }` hoặc click vào `label` bọc ngoài.

### 5c. Bảng người dùng

- Mặc định hiển thị **10 dòng/trang**
- Search theo account id hoạt động tốt: `txt-tim-nguoi-dung` = `"ecm08"` → 1 dòng
  `Lê Duy Nam · ecm08@fxp.vn · Hội đồng Sáng lập Tập đoàn`
- Cột **Email** cho biết account id → dùng để map account ↔ tên hiển thị

### 5d. Nút mở modal

`pp-multi-<quyền>-orgchart-btn` **visible sẵn** (không cần hover picker) khi people-picker đang hiển thị.

> ⚠️ Trên **màn chi tiết BHS**, cả picker lẫn nút org-chart đều bị ẩn vì khối "Phân quyền truy cập"
> có thuộc tính `hidden` (xem `KHO-TAI-LIEU.md` mục 4.6) → chỉ mở được modal này từ **form Tạo mới**
> hoặc modal **Thêm thư mục** (`pp-multi-signatory-orgchart-btn`).

---

## 6. ⚠️ Chưa khảo sát

- Chọn **nhóm người dùng** *qua modal này* rồi bấm Thêm (mới xác nhận danh sách nhóm hiển thị).
  → Với case thông thường **không cần modal**: gõ **tên nhóm** thẳng vào people-picker rồi Enter,
  y hệt khi gán cho 1 user (tìm kiếm nhanh trả cả user lẫn nhóm).
- Chọn **nhiều người cùng lúc** rồi bấm Thêm.
- Phân trang của `tbl-danh-sach-nguoi-dung`.
- Tìm và chọn qua cây `Tree-sel-co-cau-to-chuc` + `txt-tim-don-vi`.

Với các thao tác thông thường, **dùng `PW.inputPeoplePicker(testId, "ecm05")`** (gõ trực tiếp vào
picker rồi Enter) nhanh và ổn định hơn — modal này chỉ cần khi case yêu cầu chọn qua cơ cấu tổ chức.
