@medipha/chat 1.0.14 → 1.0.16
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 +103 -103
- package/dist/features/composer/attachment-file-helpers.d.ts +1 -1
- package/dist/features/composer/conversation-composer.d.ts +8 -1
- package/dist/features/create-conversation/tabs/create-group-tab.d.ts +2 -1
- package/dist/features/message-list/bubble/use-reaction-name-preview.d.ts +21 -0
- package/dist/features/typing/typing-indicator.d.ts +8 -0
- package/dist/index.cjs +46 -46
- package/dist/index.js +8547 -8127
- package/dist/pages/Setting/archive/archive-helpers.d.ts +3 -1
- package/dist/pages/conversation/conversation-detail/conversation-detail.d.ts +0 -1
- package/dist/shared/components/multi-select-filter-pill.d.ts +16 -0
- package/dist/shared/hooks/use-debounced-value.d.ts +6 -0
- package/dist/shared/hooks/use-topmost-escape.d.ts +8 -0
- package/dist/store/presenceStore.d.ts +5 -0
- package/dist/styles.css +1 -1
- package/dist/utils/work-status.d.ts +9 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
# @medipha/chat
|
|
2
|
-
|
|
3
|
-
`@medipha/chat` is an embeddable React chat module for Medic-ERP. It uses the
|
|
4
|
-
ERP application's React tree, BrowserRouter, authentication, and Ant Design 4
|
|
5
|
-
installation; it does not use an iframe or create a router.
|
|
6
|
-
|
|
7
|
-
## Install
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
pnpm add @medipha/chat
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Mount in Medic-ERP
|
|
14
|
-
|
|
15
|
-
The ERP imports the Ant Design 4 stylesheet exactly once, at its application
|
|
16
|
-
entry point. The chat library deliberately does not import it.
|
|
17
|
-
|
|
18
|
-
```tsx
|
|
19
|
-
import 'antd/dist/antd.css';
|
|
20
|
-
import { ChatModule } from '@medipha/chat';
|
|
21
|
-
import '@medipha/chat/styles.css';
|
|
22
|
-
|
|
23
|
-
<Route
|
|
24
|
-
path="/chat-erp/*"
|
|
25
|
-
element={
|
|
26
|
-
<ChatModule
|
|
27
|
-
accessToken={accessToken}
|
|
28
|
-
apiUrl={CHAT_API_URL}
|
|
29
|
-
socketUrl={CHAT_SOCKET_URL}
|
|
30
|
-
onUnauthorized={handleUnauthorized}
|
|
31
|
-
onNavigateOutsideChat={handleNavigateOutsideChat}
|
|
32
|
-
/>
|
|
33
|
-
}
|
|
34
|
-
/>;
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
The ERP must own the surrounding `BrowserRouter`. `ChatModule` adds only
|
|
38
|
-
relative routes: `/chat-erp` for the conversation list and
|
|
39
|
-
`/chat-erp/:conversationId` for a room.
|
|
40
|
-
|
|
41
|
-
## `ChatModuleProps`
|
|
42
|
-
|
|
43
|
-
| Prop | Required | Meaning |
|
|
44
|
-
| ----------------------- | -------- | --------------------------------------------------------- |
|
|
45
|
-
| `accessToken` | Yes | Current ERP access token used by chat API/socket clients. |
|
|
46
|
-
| `apiUrl` | Yes | Base URL for the Chat HTTP API. |
|
|
47
|
-
| `socketUrl` | Yes | Socket server URL. |
|
|
48
|
-
| `onUnauthorized` | No | ERP callback for an unauthorized chat response. |
|
|
49
|
-
| `onNavigateOutsideChat` | No | ERP callback for navigation that leaves chat. |
|
|
50
|
-
|
|
51
|
-
Pass a new `accessToken` prop whenever ERP refreshes its credential.
|
|
52
|
-
`ChatModule` updates its internal runtime context from the new prop and never
|
|
53
|
-
writes a token to `localStorage` or `sessionStorage`.
|
|
54
|
-
|
|
55
|
-
## Nginx SPA fallback
|
|
56
|
-
|
|
57
|
-
Configure the ERP server so deep links under `/chat-erp/*` return the ERP
|
|
58
|
-
application entry file:
|
|
59
|
-
|
|
60
|
-
```nginx
|
|
61
|
-
location / {
|
|
62
|
-
try_files $uri $uri/ /index.html;
|
|
63
|
-
}
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Development and validation
|
|
67
|
-
|
|
68
|
-
Vite 8 requires Node.js `20.19+` or `22.12+`.
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
pnpm install
|
|
72
|
-
pnpm dev
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
`pnpm dev` opens the root development playground. It loads `ChatModule`
|
|
76
|
-
directly from `src`, so library code and CSS changes use Vite HMR without a
|
|
77
|
-
library build after every edit. The playground's `BrowserRouter` is
|
|
78
|
-
development-only; it is not part of the published package.
|
|
79
|
-
|
|
80
|
-
To validate the publishable library:
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
pnpm typecheck
|
|
84
|
-
pnpm build
|
|
85
|
-
npm pack --dry-run
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
To verify the CRA host after building the library:
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
cd examples/erp-host
|
|
92
|
-
pnpm install
|
|
93
|
-
pnpm build
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Publish
|
|
97
|
-
|
|
98
|
-
Publish `@medipha/chat-core` before `@medipha/chat`. GitLab CI uses a masked,
|
|
99
|
-
protected `NPM_TOKEN` variable with npm publish permission and runs only for a
|
|
100
|
-
version tag such as `v0.1.0`. Update versions using semantic versioning: patch
|
|
101
|
-
for fixes, minor for backward-compatible features, and major for breaking API
|
|
102
|
-
changes. Create and push the version tag through your normal release process
|
|
103
|
-
after reviewing the working tree.
|
|
1
|
+
# @medipha/chat
|
|
2
|
+
|
|
3
|
+
`@medipha/chat` is an embeddable React chat module for Medic-ERP. It uses the
|
|
4
|
+
ERP application's React tree, BrowserRouter, authentication, and Ant Design 4
|
|
5
|
+
installation; it does not use an iframe or create a router.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @medipha/chat
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Mount in Medic-ERP
|
|
14
|
+
|
|
15
|
+
The ERP imports the Ant Design 4 stylesheet exactly once, at its application
|
|
16
|
+
entry point. The chat library deliberately does not import it.
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import 'antd/dist/antd.css';
|
|
20
|
+
import { ChatModule } from '@medipha/chat';
|
|
21
|
+
import '@medipha/chat/styles.css';
|
|
22
|
+
|
|
23
|
+
<Route
|
|
24
|
+
path="/chat-erp/*"
|
|
25
|
+
element={
|
|
26
|
+
<ChatModule
|
|
27
|
+
accessToken={accessToken}
|
|
28
|
+
apiUrl={CHAT_API_URL}
|
|
29
|
+
socketUrl={CHAT_SOCKET_URL}
|
|
30
|
+
onUnauthorized={handleUnauthorized}
|
|
31
|
+
onNavigateOutsideChat={handleNavigateOutsideChat}
|
|
32
|
+
/>
|
|
33
|
+
}
|
|
34
|
+
/>;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The ERP must own the surrounding `BrowserRouter`. `ChatModule` adds only
|
|
38
|
+
relative routes: `/chat-erp` for the conversation list and
|
|
39
|
+
`/chat-erp/:conversationId` for a room.
|
|
40
|
+
|
|
41
|
+
## `ChatModuleProps`
|
|
42
|
+
|
|
43
|
+
| Prop | Required | Meaning |
|
|
44
|
+
| ----------------------- | -------- | --------------------------------------------------------- |
|
|
45
|
+
| `accessToken` | Yes | Current ERP access token used by chat API/socket clients. |
|
|
46
|
+
| `apiUrl` | Yes | Base URL for the Chat HTTP API. |
|
|
47
|
+
| `socketUrl` | Yes | Socket server URL. |
|
|
48
|
+
| `onUnauthorized` | No | ERP callback for an unauthorized chat response. |
|
|
49
|
+
| `onNavigateOutsideChat` | No | ERP callback for navigation that leaves chat. |
|
|
50
|
+
|
|
51
|
+
Pass a new `accessToken` prop whenever ERP refreshes its credential.
|
|
52
|
+
`ChatModule` updates its internal runtime context from the new prop and never
|
|
53
|
+
writes a token to `localStorage` or `sessionStorage`.
|
|
54
|
+
|
|
55
|
+
## Nginx SPA fallback
|
|
56
|
+
|
|
57
|
+
Configure the ERP server so deep links under `/chat-erp/*` return the ERP
|
|
58
|
+
application entry file:
|
|
59
|
+
|
|
60
|
+
```nginx
|
|
61
|
+
location / {
|
|
62
|
+
try_files $uri $uri/ /index.html;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Development and validation
|
|
67
|
+
|
|
68
|
+
Vite 8 requires Node.js `20.19+` or `22.12+`.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pnpm install
|
|
72
|
+
pnpm dev
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`pnpm dev` opens the root development playground. It loads `ChatModule`
|
|
76
|
+
directly from `src`, so library code and CSS changes use Vite HMR without a
|
|
77
|
+
library build after every edit. The playground's `BrowserRouter` is
|
|
78
|
+
development-only; it is not part of the published package.
|
|
79
|
+
|
|
80
|
+
To validate the publishable library:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pnpm typecheck
|
|
84
|
+
pnpm build
|
|
85
|
+
npm pack --dry-run
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
To verify the CRA host after building the library:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
cd examples/erp-host
|
|
92
|
+
pnpm install
|
|
93
|
+
pnpm build
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Publish
|
|
97
|
+
|
|
98
|
+
Publish `@medipha/chat-core` before `@medipha/chat`. GitLab CI uses a masked,
|
|
99
|
+
protected `NPM_TOKEN` variable with npm publish permission and runs only for a
|
|
100
|
+
version tag such as `v0.1.0`. Update versions using semantic versioning: patch
|
|
101
|
+
for fixes, minor for backward-compatible features, and major for breaking API
|
|
102
|
+
changes. Create and push the version tag through your normal release process
|
|
103
|
+
after reviewing the working tree.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PendingAttachment } from './pending-attachment';
|
|
2
|
-
export declare const ACCEPT_ATTRIBUTE = ".jpg,.jpeg,.png,.webp,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt";
|
|
2
|
+
export declare const ACCEPT_ATTRIBUTE = ".jpg,.jpeg,.png,.webp,.gif,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.csv,.zip,.rar,.mp4,.mp3";
|
|
3
3
|
export declare const ACCEPTED_FILE_EXTENSIONS: Set<string>;
|
|
4
4
|
export declare const getFileExtension: (file: File) => string;
|
|
5
5
|
export declare const isImageFile: (file: File) => boolean;
|
|
@@ -12,9 +12,16 @@ interface ConversationComposerProps {
|
|
|
12
12
|
onError?: (message: string) => void;
|
|
13
13
|
onAttach?: () => void;
|
|
14
14
|
onAttachImages?: () => void;
|
|
15
|
+
/** Stages pasted image file(s) exactly like the attach-image button/drop would. */
|
|
16
|
+
onPasteFiles?: (files: File[]) => void;
|
|
15
17
|
onTypingStart?: () => void;
|
|
16
18
|
onTypingStop?: () => void;
|
|
17
19
|
}
|
|
20
|
+
export interface ConversationComposerHandle {
|
|
21
|
+
/** Returns the caret to the editor — used after staging an attachment, where focus
|
|
22
|
+
* otherwise stays on the attach button (or the file dialog that just closed). */
|
|
23
|
+
focus: () => void;
|
|
24
|
+
}
|
|
18
25
|
/** Rich-text composer that emits backend message content, with real @mentions. */
|
|
19
|
-
export declare
|
|
26
|
+
export declare const ConversationComposer: import('react').ForwardRefExoticComponent<ConversationComposerProps & import('react').RefAttributes<ConversationComposerHandle>>;
|
|
20
27
|
export {};
|
|
@@ -6,8 +6,9 @@ interface CreateGroupTabProps {
|
|
|
6
6
|
isLoadingUsers: boolean;
|
|
7
7
|
error: string;
|
|
8
8
|
onSubmit: (title: string, memberIds: string[], isVerified: boolean) => void;
|
|
9
|
+
onInvalidTitle: () => void;
|
|
9
10
|
}
|
|
10
11
|
/** "Nhóm" tab — check off members, submit to create the group (title input lives in the
|
|
11
12
|
* parent panel, above the department/branch filters). */
|
|
12
|
-
export declare function CreateGroupTab({ users, groupTitle, isCreating, isLoadingUsers, error, onSubmit, }: CreateGroupTabProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare function CreateGroupTab({ users, groupTitle, isCreating, isLoadingUsers, error, onSubmit, onInvalidTitle, }: CreateGroupTabProps): import("react/jsx-runtime").JSX.Element;
|
|
13
14
|
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** How many reactor names the hover tooltip shows before collapsing the rest into
|
|
2
|
+
* "và N người khác" — matches BADGE_ICON_LIMIT in message-reactions.tsx so the tooltip
|
|
3
|
+
* reads as an expansion of the same overlapping icons the badge already shows. */
|
|
4
|
+
export declare const REACTION_NAME_PREVIEW_LIMIT = 3;
|
|
5
|
+
interface ReactionNamePreview {
|
|
6
|
+
names: string[];
|
|
7
|
+
totalCount: number;
|
|
8
|
+
}
|
|
9
|
+
/** Lazily loads just enough reactor names to fill the aggregate reaction badge's hover
|
|
10
|
+
* tooltip. There can be hundreds of messages in a timeline, so this only fetches when a
|
|
11
|
+
* given badge is actually hovered (call `load()` from the hover handler) — never eagerly
|
|
12
|
+
* for messages nobody looks at — and caches the result per message so re-hovering the
|
|
13
|
+
* same badge doesn't refetch. `requestRef` mirrors the stale-response guard already used
|
|
14
|
+
* in use-reaction-modal.ts: if `load()` is called again for this message before the first
|
|
15
|
+
* call resolves, the earlier response is ignored when it lands. */
|
|
16
|
+
export declare function useReactionNamePreview(messageId: string | null): {
|
|
17
|
+
preview: ReactionNamePreview | null;
|
|
18
|
+
isLoading: boolean;
|
|
19
|
+
load: () => void;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface TypingIndicatorProps {
|
|
2
|
+
typingNames: string[];
|
|
3
|
+
}
|
|
4
|
+
/** Sits in normal flow between the timeline and the composer toolbar (Messenger/Zalo
|
|
5
|
+
* style) instead of floating over the message list — the name(s) typing, plus a small
|
|
6
|
+
* bubble of three bouncing dots standing in for "...". */
|
|
7
|
+
export declare function TypingIndicator({ typingNames }: TypingIndicatorProps): import("react/jsx-runtime").JSX.Element | null;
|
|
8
|
+
export {};
|