@namphuongtechnologi/np-hub 0.1.1 → 0.1.2

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/README.md CHANGED
@@ -1,34 +1,55 @@
1
1
  # NP Hub
2
2
 
3
- NP Hub là thư viện Web Component, không phụ thuộc framework, thể nhúng vào **web tĩnh**, **React** và các frontend stack chạy JavaScript trên trình duyệt.
3
+ NP Hub là widget hỗ trợ dạng nút nổi góc dưới phải. Nhúng được vào **web tĩnh** hoặc **React**.
4
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ợ.
5
+ ---
6
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.
7
+ ## A) Web tĩnh (HTML)
8
8
 
9
- ## Cài đặt
9
+ Không cần `npm install`. Tạo **một file JS** cấu hình, rồi nhúng vào `index.html`.
10
10
 
11
- ```bash
12
- npm install @namphuongtechnologi/np-hub
13
- ```
11
+ **`np-hub.js`** — load thư viện từ CDN và cấu hình tại đây:
14
12
 
15
- ---
13
+ ```js
14
+ var NP_HUB_CDN =
15
+ "https://cdn.jsdelivr.net/npm/@namphuongtechnologi/np-hub@0.1.1/dist/np-hub.min.global.js";
16
16
 
17
- ## A) Tích hợp web tĩnh (HTML)
17
+ function initNpHub() {
18
+ var widget = document.createElement("np-hub");
19
+ widget.setAttribute("project-id", "NPP"); // bắt buộc
20
+ // widget.setAttribute("is-dev", ""); // bỏ comment nếu dùng API dev
21
+ document.body.appendChild(widget);
18
22
 
19
- Dùng khi website không có bundler (HTML thuần, WordPress, landing page tĩnh, v.v.).
23
+ widget.setUser({
24
+ name: "Nguyen Van A",
25
+ email: "a@gmail.com",
26
+ phoneNumber: "0912345678",
27
+ });
20
28
 
21
- ### Bước 1 — Lấy file bundle
29
+ widget.setFormPrefill({
30
+ content: "Mô tả sự cố cần hỗ trợ...",
31
+ attachments: [],
32
+ priority: 0,
33
+ coordinators: [],
34
+ emailContacts: [],
35
+ });
22
36
 
23
- Sau khi cài package, copy file bundle từ `node_modules`:
37
+ widget.addEventListener("np-hub-submit-success", function (event) {
38
+ console.log("Tạo yêu cầu thành công:", event.detail);
39
+ });
24
40
 
25
- ```
26
- node_modules/@namphuongtechnologi/np-hub/dist/np-hub.min.global.js
27
- ```
41
+ widget.addEventListener("np-hub-submit-error", function (event) {
42
+ console.error("Lỗi gửi yêu cầu:", event.detail);
43
+ });
44
+ }
28
45
 
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`).
46
+ var script = document.createElement("script");
47
+ script.src = NP_HUB_CDN;
48
+ script.onload = initNpHub;
49
+ document.head.appendChild(script);
50
+ ```
30
51
 
31
- ### Bước 2 Nhúng vào trang HTML
52
+ **`index.html`**chỉ cần một dòng:
32
53
 
33
54
  ```html
34
55
  <!doctype html>
@@ -36,240 +57,86 @@ Host file này lên CDN hoặc static server của bạn (ví dụ `https://cdn.
36
57
  <head>
37
58
  <meta charset="UTF-8" />
38
59
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
39
- <title>NP Hub</title>
60
+ <title>My Site</title>
40
61
  </head>
41
62
  <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>
63
+ <script src="./np-hub.js"></script>
74
64
  </body>
75
65
  </html>
76
66
  ```
77
67
 
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 })` |
68
+ dụ đầy đủ: `examples/static-html/`.
88
69
 
89
70
  ---
90
71
 
91
- ## B) Tích hợp React
92
-
93
- Dùng khi app React có bundler (Vite, Next.js, CRA, v.v.).
72
+ ## B) React
94
73
 
95
- ### Bước 1 — Import widget
96
-
97
- ```ts
98
- import "@namphuongtechnologi/np-hub/widget";
74
+ ```bash
75
+ npm install @namphuongtechnologi/np-hub
99
76
  ```
100
77
 
101
- Dòng import này đăng 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
78
+ Import `SupportWidget` đặt **một lần** root app (ví dụ `App.tsx`, `main.tsx` hoặc root layout):
104
79
 
105
80
  ```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 />;
81
+ import { SupportWidget } from "@namphuongtechnologi/np-hub/react";
82
+
83
+ export default function App() {
84
+ return (
85
+ <>
86
+ {/* nội dung app */}
87
+ <SupportWidget
88
+ projectId="NPP"
89
+ isDev
90
+ user={{
91
+ name: "Nguyen Van A",
92
+ email: "a@gmail.com",
93
+ phoneNumber: "0912345678",
94
+ }}
95
+ formPrefill={{
96
+ content: "Mô tả sự cố cần hỗ trợ...",
97
+ attachments: [],
98
+ priority: 0,
99
+ coordinators: [],
100
+ emailContacts: [],
101
+ }}
102
+ onSubmitSuccess={(detail) => console.log("Thành công:", detail)}
103
+ onSubmitError={(error) => console.error("Lỗi:", error)}
104
+ />
105
+ </>
106
+ );
148
107
  }
149
108
  ```
150
109
 
151
- Render `<SupportWidgetHost />` một lần trong layout (ví dụ `App.tsx` hoặc root layout).
110
+ ### Props
152
111
 
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 |
112
+ | Prop | Bắt buộc | tả |
113
+ | -------------------- | -------- | --------------------------------------------- |
114
+ | `projectId` | Có | dự án |
115
+ | `isDev` | Không | `true` = API Development; mặc định Production |
116
+ | `user` | Không | Điền sẵn tên, email, SĐT |
117
+ | `formPrefill` | Không | Điền sẵn nội dung form |
118
+ | `width` / `height` | Không | Kích thước nút nổi (mặc định `72px`) |
119
+ | `onSubmitSuccess` | Không | Callback khi gửi thành công |
120
+ | `onSubmitError` | Không | Callback khi gửi lỗi |
121
+ | `onOpen` / `onClose` | Không | Callback khi mở/đóng modal |
186
122
 
187
123
  ---
188
124
 
189
125
  ## Cấu hình API
190
126
 
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` |
127
+ | Môi trường | URL |
128
+ | -------------------------------- | --------------------------------------------- |
129
+ | Production (mặc định) | `https://namphuong-api.azurewebsites.net` |
130
+ | Development (`is-dev` / `isDev`) | `https://namphuong-api-dev.azurewebsites.net` |
263
131
 
264
132
  ## Xử lý sự cố
265
133
 
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` |
134
+ | Lỗi | Cách xử lý |
135
+ | ------------------------------------------ | -------------------------------------------------------- |
136
+ | `projectId is required.` | Kiểm tra `project-id` / `projectId` |
137
+ | `user.name/email/phoneNumber is required.` | Truyền `user` hoặc để người dùng nhập đủ |
138
+ | `Content is required.` | Người dùng cần nhập nội dung trước khi submit |
139
+ | Gọi API thất bại | Kiểm tra `is-dev` / `isDev` nếu đang test môi trường dev |
273
140
 
274
141
  ## License
275
142
 
package/dist/index.d.cts CHANGED
@@ -1,83 +1,5 @@
1
1
  export { registerSupportWidget } from './register.cjs';
2
-
3
- interface SupportUser {
4
- name: string;
5
- email: string;
6
- phoneNumber: string;
7
- }
8
- interface SupportWidgetConfig {
9
- projectId: string;
10
- isDev?: boolean;
11
- }
12
- interface SupportSubmissionInput {
13
- content: string;
14
- attachments: string[];
15
- priority?: number;
16
- coordinators?: string[];
17
- emailContacts?: string[];
18
- }
19
- interface SupportRequestPayload {
20
- Requester: string;
21
- PhoneNumber: string;
22
- Email: string;
23
- Content: string;
24
- ProjectId: string;
25
- Priority: number;
26
- Attachments: string[];
27
- Coordinators: string[];
28
- EmailContacts: string[];
29
- }
30
-
31
- interface FormPrefillInput {
32
- content?: string;
33
- attachments?: string[];
34
- priority?: number;
35
- coordinators?: string[];
36
- emailContacts?: string[];
37
- }
38
- declare class SupportWidgetElement extends HTMLElement {
39
- static observedAttributes: string[];
40
- private config;
41
- private user?;
42
- private dragOccurred;
43
- private selectedFiles;
44
- private prefilledAttachments;
45
- private previewUrls;
46
- private priority;
47
- private coordinators;
48
- private emailContacts;
49
- constructor();
50
- connectedCallback(): void;
51
- disconnectedCallback(): void;
52
- attributeChangedCallback(): void;
53
- setUser(user: SupportUser): void;
54
- setFormPrefill(data: FormPrefillInput): void;
55
- open(): void;
56
- close(): void;
57
- private syncConfigFromAttributes;
58
- private bindActions;
59
- private setupPreviewControls;
60
- private setupClipboardPaste;
61
- private addSelectedFiles;
62
- private renderFileList;
63
- private buildFileItem;
64
- private fillWithFileIcon;
65
- private openPreview;
66
- private closePreview;
67
- private isImageName;
68
- private prefillFromState;
69
- private applyLauncherStyle;
70
- private normalizeSize;
71
- private setupClearableInputs;
72
- private updateClearButton;
73
- private setInputValue;
74
- private getInputValue;
75
- private submit;
76
- private setupDrag;
77
- private adjustPosition;
78
- private restorePosition;
79
- private handleResize;
80
- }
2
+ export { S as SupportRequestPayload, a as SupportSubmissionInput, b as SupportUser, c as SupportWidgetConfig, d as SupportWidgetElement } from './support-widget.element-Bsd2Uhpq.cjs';
81
3
 
82
4
  declare const WIDGET_EVENTS: {
83
5
  readonly OPEN: "np-hub-open";
@@ -86,4 +8,4 @@ declare const WIDGET_EVENTS: {
86
8
  readonly SUBMIT_ERROR: "np-hub-submit-error";
87
9
  };
88
10
 
89
- export { type SupportRequestPayload, type SupportSubmissionInput, type SupportUser, type SupportWidgetConfig, SupportWidgetElement, WIDGET_EVENTS };
11
+ export { WIDGET_EVENTS };
package/dist/index.d.ts CHANGED
@@ -1,83 +1,5 @@
1
1
  export { registerSupportWidget } from './register.js';
2
-
3
- interface SupportUser {
4
- name: string;
5
- email: string;
6
- phoneNumber: string;
7
- }
8
- interface SupportWidgetConfig {
9
- projectId: string;
10
- isDev?: boolean;
11
- }
12
- interface SupportSubmissionInput {
13
- content: string;
14
- attachments: string[];
15
- priority?: number;
16
- coordinators?: string[];
17
- emailContacts?: string[];
18
- }
19
- interface SupportRequestPayload {
20
- Requester: string;
21
- PhoneNumber: string;
22
- Email: string;
23
- Content: string;
24
- ProjectId: string;
25
- Priority: number;
26
- Attachments: string[];
27
- Coordinators: string[];
28
- EmailContacts: string[];
29
- }
30
-
31
- interface FormPrefillInput {
32
- content?: string;
33
- attachments?: string[];
34
- priority?: number;
35
- coordinators?: string[];
36
- emailContacts?: string[];
37
- }
38
- declare class SupportWidgetElement extends HTMLElement {
39
- static observedAttributes: string[];
40
- private config;
41
- private user?;
42
- private dragOccurred;
43
- private selectedFiles;
44
- private prefilledAttachments;
45
- private previewUrls;
46
- private priority;
47
- private coordinators;
48
- private emailContacts;
49
- constructor();
50
- connectedCallback(): void;
51
- disconnectedCallback(): void;
52
- attributeChangedCallback(): void;
53
- setUser(user: SupportUser): void;
54
- setFormPrefill(data: FormPrefillInput): void;
55
- open(): void;
56
- close(): void;
57
- private syncConfigFromAttributes;
58
- private bindActions;
59
- private setupPreviewControls;
60
- private setupClipboardPaste;
61
- private addSelectedFiles;
62
- private renderFileList;
63
- private buildFileItem;
64
- private fillWithFileIcon;
65
- private openPreview;
66
- private closePreview;
67
- private isImageName;
68
- private prefillFromState;
69
- private applyLauncherStyle;
70
- private normalizeSize;
71
- private setupClearableInputs;
72
- private updateClearButton;
73
- private setInputValue;
74
- private getInputValue;
75
- private submit;
76
- private setupDrag;
77
- private adjustPosition;
78
- private restorePosition;
79
- private handleResize;
80
- }
2
+ export { S as SupportRequestPayload, a as SupportSubmissionInput, b as SupportUser, c as SupportWidgetConfig, d as SupportWidgetElement } from './support-widget.element-Bsd2Uhpq.js';
81
3
 
82
4
  declare const WIDGET_EVENTS: {
83
5
  readonly OPEN: "np-hub-open";
@@ -86,4 +8,4 @@ declare const WIDGET_EVENTS: {
86
8
  readonly SUBMIT_ERROR: "np-hub-submit-error";
87
9
  };
88
10
 
89
- export { type SupportRequestPayload, type SupportSubmissionInput, type SupportUser, type SupportWidgetConfig, SupportWidgetElement, WIDGET_EVENTS };
11
+ export { WIDGET_EVENTS };