AgendaItem
Mẫu chuẩnMột dòng trong buổi Họp 1:1: loại mục, một câu nói việc gì, một liên kết tới bằng chứng trên dòng thời gian, và — chỉ với đề xuất — ba nút quyết: Duyệt, Từ chối, Để sau. Composite báo quyết định qua một callback onDecide; nó không gọi server.
Playground
Chọn kind "proposal" và "Chưa quyết" để thấy ba nút quyết; chọn một quyết định để thấy StatusDot thay rail.
Chưa quyết.
import { AgendaItem } from "@nexobox/ui";
<AgendaItem
id="agenda-1"
kind="proposal"
title="Đề xuất giảm giá tới 10% cho khách hỏi lại lần hai"
description="Nexi đã áp dụng thử trên 6 hội thoại tuần này, không có khiếu nại."
evidenceHref="/timeline/agenda-1"
evaluation={{ label: "9/10", passed: true }}
decision={null}
onDecide={(id, decision) => handleDecide(id, decision)}
/>Bài toán
Chủ shop không đọc danh sách learning candidate. Họ ngồi xuống mười phút mỗi tuần với nhân viên. Mỗi dòng trong buổi đó phải đọc được trong hai giây và quyết được trong một cú bấm, kèm đường về bằng chứng để không phải tin suông.
Khi nào sử dụng
Nên dùng
Trang Họp 1:1, bốn nhóm: Làm tốt, Sự cố, Đang chờ bạn, Đề xuất thay đổi. Tối đa khoảng mười dòng một buổi.
Khi nào không dùng
Tránh dùng
| Không dùng cho | Dùng thay |
|---|---|
| Hàng đợi phê duyệt | decision-card của Decision Spine |
| Thông báo | Notification Feed theo decision-contract.md |
Dựng từ
| Primitive tầng 1 | Vai trong composite |
|---|---|
| Card | Hàng |
| Badge | Loại mục, 72px cố định bên trái |
| Button | Ba nút quyết — secondary cho Duyệt, ghost cho Từ chối và Để sau, size sm |
| StatusDot | Trạng thái sau khi đã quyết |
| Ghi chú triển khai |
|---|
StatusDot không có variant "danger"; quyết định "Đã từ chối" dùng gần nhất là inactive (chấm xám) thay vì một chấm đỏ. |
Anatomy
| # | Phần | Ghi chú |
|---|---|---|
| 1 | Kind badge | Trái, 72px cố định: Làm tốt (success), Sự cố (danger), Đang chờ (warning), Đề xuất (information) |
| 2 | Body | Tiêu đề một dòng, mô tả tối đa hai dòng; với đề xuất thêm dòng "Đánh giá độc lập" từ evaluation |
| 3 | Evidence link | Icon mũi tên và "Xem trên dòng thời gian", href do caller truyền |
| 4 | Decision rail | Phải, chỉ khi kind === "proposal" và decision == null: ba Button size sm |
| 5 | Recalled | Khi recalledFrom có giá trị, một dòng nhạt trên cùng |
States
| State | Hành vi | Trợ năng |
|---|---|---|
| Open proposal | Ba nút hiện | role="listitem"; nhóm nút role="group" aria-label="Quyết định cho {title}" |
| Busy | Nút disabled, Button loading state | aria-busy |
| Decided | Rail thành StatusDot + chữ | aria-live="polite" khi đổi |
| Not a proposal | Không có rail | — |
Bàn phím & trợ năng
Seam — host sở hữu gì
Composite không gọi server. Host sở hữu onDecide và đưa quyết định vào approveRelease rồi vào Decision Spine như mọi quyết định khác (ADR-WF-003 clause 5).
API & triển khai
| Prop | Mặc định | Quy ước |
|---|---|---|
| id | — | Bắt buộc. |
| kind | — | "well" | "incident" | "waiting" | "proposal". |
| title | — | Bắt buộc, một dòng. |
| description | undefined | Tối đa hai dòng. |
| evidenceHref | undefined | Không hiện liên kết nếu bỏ trống. |
| evaluation | undefined | Chỉ đọc khi kind là proposal. |
| decision | null | { value, at } | null. |
| recalledFrom | undefined | Nhãn tuần ISO. |
| onDecide | undefined | (id, decision) => void. |
| busy | false | Vô hiệu cả ba nút và bật loading. |
Design tokens
--nf-semantic-text-muted (thay cho foreground-muted), --nf-foundation-space-3, --nf-foundation-typography-caption-*. Badge dùng trực tiếp bốn variant success, danger, warning, information — không cần token màu rời. Qua Card: --nf-component-card-*. Qua Button: --nf-component-button-*.
Do / Don't
Nên dùng
Mỗi dòng đọc được trong hai giây. Luôn kèm evidenceHref. Tối đa mười dòng một buổi.
Tránh dùng
Hiện rail quyết cho kind không phải proposal. Nhồi quá mười dòng — đó là lỗi của bộ soạn, không phải của composite.