@namphuongtechnologi/np-hub 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +276 -0
- package/dist/chunk-ZZ63ZHC7.js +612 -0
- package/dist/chunk-ZZ63ZHC7.js.map +1 -0
- package/dist/index.cjs +640 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +89 -0
- package/dist/index.d.ts +89 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/np-hub.min.global.js +802 -0
- package/dist/register.cjs +636 -0
- package/dist/register.cjs.map +1 -0
- package/dist/register.d.cts +3 -0
- package/dist/register.d.ts +3 -0
- package/dist/register.js +7 -0
- package/dist/register.js.map +1 -0
- package/docs/DEVELOPER_GUIDE.md +91 -0
- package/docs/PUBLIC_RELEASE.md +84 -0
- package/docs/USAGE_STATIC_REACT.md +216 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# NP Hub
|
|
2
|
+
|
|
3
|
+
NP Hub là thư viện Web Component, không phụ thuộc framework, có thể nhúng vào **web tĩnh**, **React** và các frontend stack chạy JavaScript trên trình duyệt.
|
|
4
|
+
|
|
5
|
+
Widget hiển thị dưới dạng **nút tròn nổi** ở góc dưới bên phải màn hình. Khi người dùng nhấn vào nút, một **modal form** mở ra để điền thông tin và gửi yêu cầu hỗ trợ.
|
|
6
|
+
|
|
7
|
+
Toàn bộ giao diện (logo, CSS, layout) do thư viện quản lý. Website tích hợp chỉ cần cung cấp cấu hình API và thông tin form; không cần và không thể tuỳ biến logo hay style.
|
|
8
|
+
|
|
9
|
+
## Cài đặt
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install @namphuongtechnologi/np-hub
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## A) Tích hợp web tĩnh (HTML)
|
|
18
|
+
|
|
19
|
+
Dùng khi website không có bundler (HTML thuần, WordPress, landing page tĩnh, v.v.).
|
|
20
|
+
|
|
21
|
+
### Bước 1 — Lấy file bundle
|
|
22
|
+
|
|
23
|
+
Sau khi cài package, copy file bundle từ `node_modules`:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
node_modules/@namphuongtechnologi/np-hub/dist/np-hub.min.global.js
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Host file này lên CDN hoặc static server của bạn (ví dụ `https://cdn.example.com/np-hub.min.global.js`).
|
|
30
|
+
|
|
31
|
+
### Bước 2 — Nhúng vào trang HTML
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<!doctype html>
|
|
35
|
+
<html lang="vi">
|
|
36
|
+
<head>
|
|
37
|
+
<meta charset="UTF-8" />
|
|
38
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
39
|
+
<title>NP Hub</title>
|
|
40
|
+
</head>
|
|
41
|
+
<body>
|
|
42
|
+
<!-- 1. Khai báo widget -->
|
|
43
|
+
<np-hub project-id="NPP" is-dev></np-hub>
|
|
44
|
+
|
|
45
|
+
<!-- 2. Load bundle (tự đăng ký custom element <np-hub>) -->
|
|
46
|
+
<script src="https://cdn.example.com/np-hub.min.global.js"></script>
|
|
47
|
+
|
|
48
|
+
<!-- 3. Cấu hình dữ liệu và lắng nghe sự kiện -->
|
|
49
|
+
<script>
|
|
50
|
+
const widget = document.querySelector("np-hub");
|
|
51
|
+
|
|
52
|
+
widget.setUser({
|
|
53
|
+
name: "Nguyen Van A",
|
|
54
|
+
email: "a@gmail.com",
|
|
55
|
+
phoneNumber: "0912345678",
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
widget.setFormPrefill({
|
|
59
|
+
content: "Mô tả sự cố cần hỗ trợ...",
|
|
60
|
+
attachments: ["https://files.example.com/attachment-1.png"],
|
|
61
|
+
priority: 0,
|
|
62
|
+
coordinators: [],
|
|
63
|
+
emailContacts: [],
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
widget.addEventListener("np-hub-submit-success", (event) => {
|
|
67
|
+
console.log("Tạo yêu cầu thành công:", event.detail);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
widget.addEventListener("np-hub-submit-error", (event) => {
|
|
71
|
+
console.error("Lỗi gửi yêu cầu:", event.detail);
|
|
72
|
+
});
|
|
73
|
+
</script>
|
|
74
|
+
</body>
|
|
75
|
+
</html>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Ghi chú web tĩnh
|
|
79
|
+
|
|
80
|
+
| Mục | Chi tiết |
|
|
81
|
+
| ------------------ | ------------------------------------------------------------------------------------------------- |
|
|
82
|
+
| Bundle | `dist/np-hub.min.global.js` — IIFE, không cần import |
|
|
83
|
+
| `project-id` | Bắt buộc — mã dự án trên hệ thống hỗ trợ |
|
|
84
|
+
| `is-dev` | Boolean attribute — dùng API Development; bỏ qua để dùng Production mặc định |
|
|
85
|
+
| `setUser()` | Điền sẵn thông tin người gửi; người dùng vẫn có thể sửa |
|
|
86
|
+
| `setFormPrefill()` | Điền sẵn nội dung form; người dùng vẫn có thể sửa |
|
|
87
|
+
| Đính kèm | Người dùng upload file trực tiếp trên form, hoặc truyền URL qua `setFormPrefill({ attachments })` |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## B) Tích hợp React
|
|
92
|
+
|
|
93
|
+
Dùng khi app React có bundler (Vite, Next.js, CRA, v.v.).
|
|
94
|
+
|
|
95
|
+
### Bước 1 — Import widget
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import "@namphuongtechnologi/np-hub/widget";
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Dòng import này đăng ký custom element `<np-hub>` — chỉ cần gọi **một lần** ở entry hoặc component host.
|
|
102
|
+
|
|
103
|
+
### Bước 2 — Tạo component host
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
import { useEffect, useRef } from "react";
|
|
107
|
+
import type { SupportWidgetElement } from "@namphuongtechnologi/np-hub";
|
|
108
|
+
import "@namphuongtechnologi/np-hub/widget";
|
|
109
|
+
|
|
110
|
+
export function SupportWidgetHost() {
|
|
111
|
+
const widgetRef = useRef<SupportWidgetElement>(null);
|
|
112
|
+
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
const el = widgetRef.current;
|
|
115
|
+
if (!el) return;
|
|
116
|
+
|
|
117
|
+
el.setUser({
|
|
118
|
+
name: "Nguyen Van A",
|
|
119
|
+
email: "a@gmail.com",
|
|
120
|
+
phoneNumber: "0912345678",
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
el.setFormPrefill({
|
|
124
|
+
content: "Mô tả sự cố cần hỗ trợ...",
|
|
125
|
+
attachments: ["https://files.example.com/attachment-1.png"],
|
|
126
|
+
priority: 0,
|
|
127
|
+
coordinators: [],
|
|
128
|
+
emailContacts: [],
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const onSuccess = (event: Event) => {
|
|
132
|
+
console.log("Tạo yêu cầu thành công:", (event as CustomEvent).detail);
|
|
133
|
+
};
|
|
134
|
+
const onError = (event: Event) => {
|
|
135
|
+
console.error("Lỗi gửi yêu cầu:", (event as CustomEvent).detail);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
el.addEventListener("np-hub-submit-success", onSuccess);
|
|
139
|
+
el.addEventListener("np-hub-submit-error", onError);
|
|
140
|
+
|
|
141
|
+
return () => {
|
|
142
|
+
el.removeEventListener("np-hub-submit-success", onSuccess);
|
|
143
|
+
el.removeEventListener("np-hub-submit-error", onError);
|
|
144
|
+
};
|
|
145
|
+
}, []);
|
|
146
|
+
|
|
147
|
+
return <np-hub ref={widgetRef} project-id="NPP" is-dev />;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Render `<SupportWidgetHost />` một lần trong layout (ví dụ `App.tsx` hoặc root layout).
|
|
152
|
+
|
|
153
|
+
### TypeScript — khai báo JSX (tuỳ chọn)
|
|
154
|
+
|
|
155
|
+
Nếu TypeScript báo lỗi với thẻ `<np-hub>`, thêm file `np-hub.d.ts`:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import type { SupportWidgetElement } from "@namphuongtechnologi/np-hub";
|
|
159
|
+
|
|
160
|
+
declare module "react" {
|
|
161
|
+
namespace JSX {
|
|
162
|
+
interface IntrinsicElements {
|
|
163
|
+
"np-hub": React.DetailedHTMLProps<
|
|
164
|
+
React.HTMLAttributes<SupportWidgetElement>,
|
|
165
|
+
SupportWidgetElement
|
|
166
|
+
> & {
|
|
167
|
+
"project-id"?: string;
|
|
168
|
+
"is-dev"?: boolean;
|
|
169
|
+
width?: string | number;
|
|
170
|
+
height?: string | number;
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Ghi chú React
|
|
178
|
+
|
|
179
|
+
| Mục | Chi tiết |
|
|
180
|
+
| ------------ | ---------------------------------------------------------------------------------------- |
|
|
181
|
+
| Entry import | `@namphuongtechnologi/np-hub/widget` — side-effect, đăng ký element |
|
|
182
|
+
| Ref type | `SupportWidgetElement` export từ `@namphuongtechnologi/np-hub` |
|
|
183
|
+
| Attributes | Dùng kebab-case: `project-id`, `is-dev` |
|
|
184
|
+
| Cleanup | Luôn `removeEventListener` trong `useEffect` return |
|
|
185
|
+
| SSR | Widget chỉ chạy trên browser — render trong `useEffect` hoặc dynamic import nếu dùng SSR |
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Cấu hình API
|
|
190
|
+
|
|
191
|
+
URL API được cố định trong thư viện:
|
|
192
|
+
|
|
193
|
+
| Môi trường | URL |
|
|
194
|
+
| --- | --- |
|
|
195
|
+
| Production (mặc định) | `https://namphuong-api.azurewebsites.net` |
|
|
196
|
+
| Development | `https://namphuong-api-dev.azurewebsites.net` |
|
|
197
|
+
|
|
198
|
+
Chỉ cần truyền `is-dev` khi muốn dùng API Development. Không truyền thì dùng Production.
|
|
199
|
+
|
|
200
|
+
```html
|
|
201
|
+
<!-- Production -->
|
|
202
|
+
<np-hub project-id="NPP"></np-hub>
|
|
203
|
+
|
|
204
|
+
<!-- Development -->
|
|
205
|
+
<np-hub project-id="NPP" is-dev></np-hub>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Thuộc tính (Attributes)
|
|
209
|
+
|
|
210
|
+
| Attribute | Bắt buộc | Mô tả |
|
|
211
|
+
| -------------- | -------- | ----------------------------------------------------- |
|
|
212
|
+
| `project-id` | Có | Mã dự án |
|
|
213
|
+
| `is-dev` | Không | Boolean — dùng API Development; mặc định là Production |
|
|
214
|
+
| `width` | Không | Kích thước nút nổi; số hiểu là `px` (mặc định `72px`) |
|
|
215
|
+
| `height` | Không | Kích thước nút nổi (mặc định `72px`) |
|
|
216
|
+
|
|
217
|
+
Logo và vị trí mặc định (góc dưới phải) do thư viện quản lý. Dùng `width`/`height` để chỉnh kích thước nút.
|
|
218
|
+
|
|
219
|
+
## Phương thức
|
|
220
|
+
|
|
221
|
+
| Phương thức | Mô tả |
|
|
222
|
+
| --------------------------------------------------------------------------------- | -------------------------------------------- |
|
|
223
|
+
| `setUser({ name, email, phoneNumber })` | Điền sẵn `Requester`, `Email`, `PhoneNumber` |
|
|
224
|
+
| `setFormPrefill({ content, attachments, priority, coordinators, emailContacts })` | Điền sẵn nội dung form |
|
|
225
|
+
| `open()` | Mở modal form |
|
|
226
|
+
| `close()` | Đóng modal form |
|
|
227
|
+
|
|
228
|
+
### `setFormPrefill` input
|
|
229
|
+
|
|
230
|
+
| Trường | Kiểu | Mô tả |
|
|
231
|
+
| --------------- | ---------- | -------------------------- |
|
|
232
|
+
| `content` | `string` | Nội dung yêu cầu |
|
|
233
|
+
| `attachments` | `string[]` | URL file đính kèm gán sẵn |
|
|
234
|
+
| `priority` | `number` | Mức ưu tiên (mặc định `0`) |
|
|
235
|
+
| `coordinators` | `string[]` | Danh sách coordinator |
|
|
236
|
+
| `emailContacts` | `string[]` | Danh sách email liên hệ |
|
|
237
|
+
|
|
238
|
+
## Form và gửi API
|
|
239
|
+
|
|
240
|
+
Widget gửi request dạng `multipart/form-data` tới endpoint:
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
POST {baseUrl}/api/supportcenter/create-request-anonymous
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Các trường gửi lên:
|
|
247
|
+
|
|
248
|
+
- `Requester`, `PhoneNumber`, `Email` — từ `setUser()` hoặc người dùng nhập
|
|
249
|
+
- `Content` — nội dung yêu cầu
|
|
250
|
+
- `ProjectId` — từ `project-id`
|
|
251
|
+
- `Priority` — mức ưu tiên
|
|
252
|
+
- `Attachments` — file upload từ form và/hoặc URL truyền qua `setFormPrefill`
|
|
253
|
+
- `Coordinators`, `EmailContacts` — danh sách string
|
|
254
|
+
|
|
255
|
+
## Sự kiện
|
|
256
|
+
|
|
257
|
+
| Sự kiện | Khi nào phát ra |
|
|
258
|
+
| ----------------------- | ------------------------------------------------------- |
|
|
259
|
+
| `np-hub-open` | Mở modal |
|
|
260
|
+
| `np-hub-close` | Đóng modal |
|
|
261
|
+
| `np-hub-submit-success` | Gọi API thành công — `event.detail` chứa response |
|
|
262
|
+
| `np-hub-submit-error` | Validate hoặc gọi API thất bại — `event.detail.message` |
|
|
263
|
+
|
|
264
|
+
## Xử lý sự cố
|
|
265
|
+
|
|
266
|
+
| Lỗi | Cách xử lý |
|
|
267
|
+
| ------------------------------------------ | --------------------------------------------- |
|
|
268
|
+
| `projectId is required.` | Kiểm tra attribute `project-id` |
|
|
269
|
+
| `user.name/email/phoneNumber is required.` | Gọi `setUser(...)` hoặc để người dùng nhập đủ |
|
|
270
|
+
| `Content is required.` | Người dùng cần nhập nội dung trước khi submit |
|
|
271
|
+
| Gọi API thất bại | Kiểm tra `is-dev` nếu đang test môi trường Development |
|
|
272
|
+
| Nút quá to/nhỏ | Dùng `width`/`height` |
|
|
273
|
+
|
|
274
|
+
## License
|
|
275
|
+
|
|
276
|
+
MIT
|