@dactaiit/consent-cmp-react
v0.1.5
Published
React component để tải config consent từ API và gửi data-consent lên CMP server, có validator bắt buộc và custom CSS.
Maintainers
Readme
@dactaiit/consent-cmp-react
React component để:
- Tải cấu hình từ Config API và render checkbox + text mô tả.
- Khi tick/bỏ tick → tự động gọi CMP API gửi
data-consentlên server. - Validator giống captcha: bắt buộc tick các mục
requiredmới submit được. - Custom CSS linh hoạt: CSS variables,
classNamestừng phần tử, hoặcunstyled.
⚠️ Giả định về API (chưa được xác minh — chỉnh cho khớp backend của bạn): Các shape
ConsentConfig/ConsentPayloaddưới đây là đề xuất mặc định. Nếu backend dùng shape khác, sửasrc/types.tshoặc map dữ liệu trước khi truyền vào.
Cài đặt
npm install @dactaiit/consent-cmp-reactreact và react-dom (>= 17) là peer dependencies.
Dùng nhanh
import { ConsentInput } from '@dactaiit/consent-cmp-react';
import '@dactaiit/consent-cmp-react/styles.css'; // bỏ dòng này nếu tự style
export default function App() {
return (
<ConsentInput
configApiUrl="https://api.example.com/consent/config"
cmpApiUrl="https://api.example.com/cmp/data-consent"
apiHeaders={{ Authorization: 'Bearer ...' }}
metadata={{ userId: 'u_123', page: window.location.href }}
onSubmit={(payload) => console.log('submitted', payload)}
onError={(err) => console.error(err)}
/>
);
}Shape API (mặc định)
Config API — GET configApiUrl → trả về:
{
"title": "Đồng ý xử lý dữ liệu",
"submitLabel": "Đồng ý & Tiếp tục",
"items": [
{
"id": "marketing",
"label": "Nhận email marketing",
"description": "Chúng tôi gửi ưu đãi theo định kỳ.",
"required": false
},
{
"id": "terms",
"label": "Tôi đồng ý với Điều khoản dịch vụ",
"required": true
}
]
}CMP API — POST cmpApiUrl với body:
{
"consents": [{ "id": "terms", "granted": true }],
"timestamp": "2026-06-17T07:50:00.000Z",
"metadata": { "userId": "u_123" }
}- Khi
sendOnToggle(mặc địnhtrue): mỗi lần tick gửi 1 item. - Khi bấm submit: gửi toàn bộ trạng thái hiện tại.
Props chính
| Prop | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| configApiUrl | string | — | URL Config API (bắt buộc) |
| cmpApiUrl | string | — | URL CMP API (bắt buộc) |
| apiHeaders | Record<string,string> | — | Header cho cả 2 API (nên memo hóa) |
| metadata | Record<string,unknown> | — | Đính kèm mỗi payload |
| sendOnToggle | boolean | true | Gửi ngay mỗi lần tick |
| onSubmit | (payload) => void | — | Sau khi submit thành công |
| onChange | (state) => void | — | Khi đổi trạng thái checkbox |
| onError | (error) => void | — | Khi API lỗi |
| classNames | ConsentInputClassNames | — | Class cho từng phần tử |
| style | CSSProperties | — | Style root (tiện set CSS vars) |
| unstyled | boolean | false | Bỏ toàn bộ style mặc định |
| validationMessage | string | (mặc định tiếng Việt) | Thông báo khi thiếu mục bắt buộc |
Custom CSS — 3 cách
1) CSS variables (ghi đè nhanh màu/spacing):
<ConsentInput
style={{ ['--cmp-accent' as any]: '#16a34a', ['--cmp-radius' as any]: '4px' }}
/* ... */
/>Biến hỗ trợ: --cmp-accent, --cmp-text, --cmp-muted, --cmp-error,
--cmp-border, --cmp-radius, --cmp-gap, --cmp-font-size.
2) classNames (gắn class riêng, dùng được với Tailwind/CSS Modules):
<ConsentInput
classNames={{
root: 'my-consent',
submit: 'btn btn-primary',
checkbox: 'my-checkbox',
}}
/* ... */
/>3) unstyled (headless — tự viết 100% CSS):
<ConsentInput unstyled classNames={{ /* class của bạn */ }} /* ... */ />Validator (cơ chế "captcha")
Mục có required: true phải được tick thì nút submit mới bật.
Khi người dùng bấm submit lúc chưa đủ điều kiện, validationMessage hiển thị.
Bạn cũng có thể tự kiểm tra qua onChange.
Dùng từng phần (nâng cao)
import { useConsentConfig, sendConsent, ConsentApiError } from '@dactaiit/consent-cmp-react';useConsentConfig(url, options) → { config, loading, error }.
sendConsent(url, payload, options) → gửi thủ công, ném ConsentApiError khi lỗi.
Mock CMP API (giả lập backend)
Module mock-cmp/ mô phỏng hệ thống CMP: phục vụ config xuống client và lưu data-consent gửi lên.
Dữ liệu persist tại mock-cmp/.data/database.json (config, events, subjects, logs).
Chạy standalone
npm install
npm run mock:cmp
# → http://localhost:3100Chạy kèm demo (Vite middleware — dùng chung store file)
npm run demo:dev
# → http://localhost:5173Endpoints
| Method | Path | Mô tả |
|---|---|---|
| GET | /api/consent/config | Trả config checkbox (ConsentConfig) |
| PUT | /api/consent/config | Cập nhật config (body = ConsentConfig) |
| POST | /api/consent/config/reset | Reset config về mặc định |
| POST | /api/cmp/data-consent | Lưu consent payload, merge snapshot theo subject |
| GET | /api/cmp/data-consent | Danh sách event đã lưu (?subjectKey= lọc) |
| DELETE | /api/cmp/data-consent | Xóa toàn bộ events + subjects |
| GET | /api/cmp/subjects | Snapshot consent mới nhất theo subject |
| GET | /api/cmp/stats | Thống kê store |
| GET | /api/cmp/health | Health check |
| GET | /api/demo/logs | Log request (debug) |
| DELETE | /api/demo/logs | Xóa log |
| POST | /api/register | Giả lập đăng ký (demo form) |
Subject key (gom consent theo người dùng): ưu tiên metadata.userId → metadata.email → metadata.form → anonymous.
POST /api/cmp/data-consent — body:
{
"consents": [{ "id": "terms", "granted": true }],
"timestamp": "2026-06-17T08:00:00.000Z",
"metadata": { "email": "[email protected]", "form": "register-demo" }
}Response 201:
{
"ok": true,
"eventId": "evt_...",
"subjectKey": "email:[email protected]",
"snapshot": {
"subjectKey": "email:[email protected]",
"consents": { "terms": true },
"updatedAt": "...",
"lastEventId": "evt_..."
}
}Build
npm install
npm run build # xuất ESM + CJS + .d.ts + styles.css vào dist/
npm run typecheck