@droppii-org/chat-sdk 0.1.6 → 0.1.7
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/dist/components/cannedResponse/CannedResponseBody.d.ts.map +1 -1
- package/dist/components/cannedResponse/CannedResponseBody.js +54 -3
- package/dist/components/conversation/ConversationBySessionItem.d.ts.map +1 -1
- package/dist/components/conversation/ConversationBySessionItem.js +7 -2
- package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
- package/dist/components/conversation/DeskConversationList.js +22 -17
- package/dist/components/message/MessageHeader.d.ts +2 -2
- package/dist/components/message/MessageHeader.d.ts.map +1 -1
- package/dist/components/message/MessageHeader.js +5 -2
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +31 -22
- package/dist/components/message/SelectSession.d.ts.map +1 -1
- package/dist/components/message/SelectSession.js +7 -9
- package/dist/components/message/footer/ActionBar.d.ts.map +1 -1
- package/dist/components/message/footer/ActionBar.js +3 -2
- package/dist/components/message/footer/CannedResponsePlugin.d.ts.map +1 -1
- package/dist/components/message/footer/CannedResponsePlugin.js +37 -1
- package/dist/components/message/footer/ComposerEditor.d.ts +7 -0
- package/dist/components/message/footer/ComposerEditor.d.ts.map +1 -0
- package/dist/components/message/footer/ComposerEditor.js +13 -0
- package/dist/components/message/footer/ComposerTabs.d.ts +9 -0
- package/dist/components/message/footer/ComposerTabs.d.ts.map +1 -0
- package/dist/components/message/footer/ComposerTabs.js +37 -0
- package/dist/components/message/footer/EnterHandler.d.ts.map +1 -1
- package/dist/components/message/footer/EnterHandler.js +10 -1
- package/dist/components/message/footer/index.d.ts +2 -2
- package/dist/components/message/footer/index.d.ts.map +1 -1
- package/dist/components/message/footer/index.js +45 -9
- package/dist/components/message/item/index.d.ts.map +1 -1
- package/dist/components/message/item/index.js +11 -1
- package/dist/components/session/DeskAssignedSession.d.ts.map +1 -1
- package/dist/components/session/DeskAssignedSession.js +14 -109
- package/dist/components/session/DeskTeamInbox.d.ts +3 -0
- package/dist/components/session/DeskTeamInbox.d.ts.map +1 -0
- package/dist/components/session/DeskTeamInbox.js +56 -0
- package/dist/components/session/SessionFilterMenu.d.ts +13 -0
- package/dist/components/session/SessionFilterMenu.d.ts.map +1 -0
- package/dist/components/session/SessionFilterMenu.js +27 -0
- package/dist/components/session/sessionMenuItems.d.ts +26 -0
- package/dist/components/session/sessionMenuItems.d.ts.map +1 -0
- package/dist/components/session/sessionMenuItems.js +108 -0
- package/dist/hooks/conversation/useConversationPreview.d.ts +12 -0
- package/dist/hooks/conversation/useConversationPreview.d.ts.map +1 -0
- package/dist/hooks/conversation/useConversationPreview.js +22 -0
- package/dist/hooks/message/useConversationMessages.d.ts +27 -0
- package/dist/hooks/message/useConversationMessages.d.ts.map +1 -0
- package/dist/hooks/message/useConversationMessages.js +29 -0
- package/dist/hooks/message/useMessage.d.ts.map +1 -1
- package/dist/hooks/message/usePullSessionMessages.d.ts +9 -0
- package/dist/hooks/message/usePullSessionMessages.d.ts.map +1 -0
- package/dist/hooks/message/usePullSessionMessages.js +27 -0
- package/dist/hooks/message/useSendMessage.d.ts +8 -6
- package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
- package/dist/hooks/message/useSendMessage.js +8 -8
- package/dist/hooks/session/useConversationSessionState.d.ts +21 -0
- package/dist/hooks/session/useConversationSessionState.d.ts.map +1 -0
- package/dist/hooks/session/useConversationSessionState.js +41 -0
- package/dist/hooks/session/useGetSession.d.ts.map +1 -1
- package/dist/hooks/session/useGetSession.js +138 -52
- package/dist/hooks/session/useGetTeamSessionSummary.d.ts +3 -0
- package/dist/hooks/session/useGetTeamSessionSummary.d.ts.map +1 -0
- package/dist/hooks/session/useGetTeamSessionSummary.js +12 -0
- package/dist/hooks/session/useIsJoinedGroup.d.ts +5 -0
- package/dist/hooks/session/useIsJoinedGroup.d.ts.map +1 -0
- package/dist/hooks/session/useIsJoinedGroup.js +24 -0
- package/dist/hooks/session/useJoinGroupFlow.d.ts +12 -0
- package/dist/hooks/session/useJoinGroupFlow.d.ts.map +1 -0
- package/dist/hooks/session/useJoinGroupFlow.js +59 -0
- package/dist/hooks/session/useJoinSession.d.ts +3 -0
- package/dist/hooks/session/useJoinSession.d.ts.map +1 -0
- package/dist/hooks/session/useJoinSession.js +38 -0
- package/dist/hooks/user/useCurrentUserAccountType.d.ts +3 -0
- package/dist/hooks/user/useCurrentUserAccountType.d.ts.map +1 -0
- package/dist/hooks/user/useCurrentUserAccountType.js +30 -0
- package/dist/locales/vi/common.json +12 -2
- package/dist/services/query.d.ts +5 -0
- package/dist/services/query.d.ts.map +1 -1
- package/dist/services/query.js +5 -0
- package/dist/services/routes.d.ts +5 -0
- package/dist/services/routes.d.ts.map +1 -1
- package/dist/services/routes.js +5 -0
- package/dist/store/conversation.d.ts.map +1 -1
- package/dist/store/conversation.js +41 -12
- package/dist/store/session.js +1 -1
- package/dist/styles/global.css +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/chat.d.ts +18 -1
- package/dist/types/chat.d.ts.map +1 -1
- package/dist/types/chat.js +9 -0
- package/dist/types/dto.d.ts +87 -0
- package/dist/types/dto.d.ts.map +1 -1
- package/dist/utils/events.d.ts +1 -0
- package/dist/utils/events.d.ts.map +1 -1
- package/dist/utils/messageTransform.d.ts +5 -0
- package/dist/utils/messageTransform.d.ts.map +1 -0
- package/dist/utils/messageTransform.js +106 -0
- package/dist/utils/queryHelpers.d.ts.map +1 -1
- package/dist/utils/queryHelpers.js +2 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnterHandler.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/EnterHandler.tsx"],"names":[],"mappings":"AAuBA,MAAM,CAAC,OAAO,UAAU,YAAY,
|
|
1
|
+
{"version":3,"file":"EnterHandler.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/EnterHandler.tsx"],"names":[],"mappings":"AAuBA,MAAM,CAAC,OAAO,UAAU,YAAY,SAiHnC"}
|
|
@@ -7,9 +7,10 @@ import { $isListNode, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND
|
|
|
7
7
|
import { $isQuoteNode } from "@lexical/rich-text";
|
|
8
8
|
import { useMessageFooterContext } from ".";
|
|
9
9
|
import useConversationStore from "../../../store/conversation";
|
|
10
|
+
import { emit } from "../../../utils/events";
|
|
10
11
|
export default function EnterHandler() {
|
|
11
12
|
const [editor] = useLexicalComposerContext();
|
|
12
|
-
const { onSendMessage, listUploadFiles } = useMessageFooterContext();
|
|
13
|
+
const { onSendMessage, isInternal, listUploadFiles, isOpenCanned, activeCannedIndex, } = useMessageFooterContext();
|
|
13
14
|
const shiftEnterCount = useRef(0);
|
|
14
15
|
const quotedMessage = useConversationStore((state) => state.quotedMessage);
|
|
15
16
|
useEffect(() => {
|
|
@@ -18,6 +19,10 @@ export default function EnterHandler() {
|
|
|
18
19
|
if (!event.shiftKey) {
|
|
19
20
|
event.preventDefault();
|
|
20
21
|
shiftEnterCount.current = 0;
|
|
22
|
+
if (isOpenCanned) {
|
|
23
|
+
emit("CANNED_RESPONSE_SELECT", activeCannedIndex);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
21
26
|
let plainText = "";
|
|
22
27
|
let richText = "";
|
|
23
28
|
// lấy plain text & html
|
|
@@ -34,6 +39,7 @@ export default function EnterHandler() {
|
|
|
34
39
|
plainText,
|
|
35
40
|
richText,
|
|
36
41
|
type: hasFiles ? "file" : "text",
|
|
42
|
+
isInternal,
|
|
37
43
|
});
|
|
38
44
|
}
|
|
39
45
|
editor.update(() => {
|
|
@@ -85,6 +91,9 @@ export default function EnterHandler() {
|
|
|
85
91
|
listUploadFiles,
|
|
86
92
|
quotedMessage,
|
|
87
93
|
quotedMessage === null || quotedMessage === void 0 ? void 0 : quotedMessage.clientMsgID,
|
|
94
|
+
isInternal,
|
|
95
|
+
isOpenCanned,
|
|
96
|
+
activeCannedIndex,
|
|
88
97
|
]);
|
|
89
98
|
return null;
|
|
90
99
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MessageFooterContextType } from "../../../types/chat";
|
|
2
|
-
import {
|
|
2
|
+
import { ISessionResponse } from "../../../types/dto";
|
|
3
3
|
interface MessageFooterProps {
|
|
4
|
-
currentSession?:
|
|
4
|
+
currentSession?: ISessionResponse;
|
|
5
5
|
openCreateCannedModal?: () => void;
|
|
6
6
|
}
|
|
7
7
|
export declare const MessageFooterContext: import("react").Context<MessageFooterContextType>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/index.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAEL,wBAAwB,EACzB,MAAM,qBAAqB,CAAC;AAK7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAWtD,UAAU,kBAAkB;IAC1B,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AASD,eAAO,MAAM,oBAAoB,mDAY/B,CAAC;AAEH,eAAO,MAAM,uBAAuB,gCAAyC,CAAC;AAE9E,QAAA,MAAM,qBAAqB,GAAI,4CAG5B,kBAAkB,4CAkJpB,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
|
4
|
-
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
5
|
-
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
6
|
-
import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
|
|
7
4
|
import { ToolbarPlugin } from "./ToolbarPlugin";
|
|
8
5
|
import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin";
|
|
9
6
|
import { ListPlugin } from "@lexical/react/LexicalListPlugin";
|
|
10
7
|
import { editorTheme, editorNodes, editorOnError } from "./editorConfig";
|
|
11
|
-
import { createContext, useCallback, useContext, useState } from "react";
|
|
8
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from "react";
|
|
12
9
|
import EnterHandler from "./EnterHandler";
|
|
13
10
|
import ActionBar from "./ActionBar";
|
|
11
|
+
import { AccountType, } from "../../../types/chat";
|
|
14
12
|
import { useSendMessage } from "../../../hooks/message/useSendMessage";
|
|
15
13
|
import { Popover } from "antd";
|
|
16
14
|
import FilePreview from "./FilePreview";
|
|
@@ -21,6 +19,9 @@ import CannedResponse from "../../cannedResponse";
|
|
|
21
19
|
import { CannedResponseTriggerPlugin } from "./CannedResponsePlugin";
|
|
22
20
|
import { useBoolean } from "ahooks";
|
|
23
21
|
import useAuthStore from "../../../store/auth";
|
|
22
|
+
import { useCurrentUserAccountType } from "../../../hooks/user/useCurrentUserAccountType";
|
|
23
|
+
import ComposerTabs from "./ComposerTabs";
|
|
24
|
+
import ComposerEditor from "./ComposerEditor";
|
|
24
25
|
const initialConfig = {
|
|
25
26
|
namespace: "ChatInput",
|
|
26
27
|
theme: editorTheme,
|
|
@@ -29,22 +30,43 @@ const initialConfig = {
|
|
|
29
30
|
};
|
|
30
31
|
export const MessageFooterContext = createContext({
|
|
31
32
|
onSendMessage: () => { },
|
|
33
|
+
isInternal: false,
|
|
34
|
+
setIsInternal: () => { },
|
|
32
35
|
listUploadFiles: [],
|
|
33
36
|
setListUploadFiles: () => { },
|
|
34
37
|
isOpenCanned: false,
|
|
35
38
|
setIsOpenCanned: () => { },
|
|
39
|
+
activeCannedIndex: 0,
|
|
40
|
+
setActiveCannedIndex: () => { },
|
|
41
|
+
maxActiveCannedIndex: 0,
|
|
42
|
+
setMaxActiveCannedIndex: () => { },
|
|
36
43
|
});
|
|
37
44
|
export const useMessageFooterContext = () => useContext(MessageFooterContext);
|
|
38
45
|
const MessageFooterProvider = ({ currentSession, openCreateCannedModal, }) => {
|
|
39
46
|
const { t } = useTranslation();
|
|
40
47
|
const { sendTextMessage, sendMergeMessage } = useSendMessage();
|
|
48
|
+
const accountType = useCurrentUserAccountType();
|
|
41
49
|
const [listUploadFiles, setListUploadFiles] = useState([]);
|
|
42
|
-
const [isOpenCanned, { setTrue: openCanned, setFalse: closeCanned
|
|
50
|
+
const [isOpenCanned, { setTrue: openCanned, setFalse: closeCanned },] = useBoolean(false);
|
|
43
51
|
const isCrm = useAuthStore((state) => state.isCrm);
|
|
44
52
|
const [cannedQuery, setCannedQuery] = useState("");
|
|
45
|
-
const
|
|
53
|
+
const [activeCannedIndex, setActiveCannedIndex] = useState(0);
|
|
54
|
+
const [maxActiveCannedIndex, setMaxActiveCannedIndex] = useState(0);
|
|
55
|
+
const [isInternal, setIsInternal] = useState(false);
|
|
56
|
+
const canUseInternal = accountType === AccountType.Staff;
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (!canUseInternal && isInternal) {
|
|
59
|
+
setIsInternal(false);
|
|
60
|
+
}
|
|
61
|
+
}, [canUseInternal, isInternal]);
|
|
62
|
+
const placeholderText = useMemo(() => {
|
|
63
|
+
return isInternal
|
|
64
|
+
? t("enter_internal_message")
|
|
65
|
+
: t("enter_message");
|
|
66
|
+
}, [isInternal, t]);
|
|
67
|
+
const onSendMessage = useCallback(async ({ plainText, richText, type, isInternal, }) => {
|
|
46
68
|
if (type === "text") {
|
|
47
|
-
sendTextMessage({ plainText, richText, currentSession });
|
|
69
|
+
sendTextMessage({ plainText, richText, currentSession, isInternal });
|
|
48
70
|
}
|
|
49
71
|
else {
|
|
50
72
|
sendMergeMessage({
|
|
@@ -52,6 +74,7 @@ const MessageFooterProvider = ({ currentSession, openCreateCannedModal, }) => {
|
|
|
52
74
|
richText,
|
|
53
75
|
files: listUploadFiles,
|
|
54
76
|
currentSession,
|
|
77
|
+
isInternal,
|
|
55
78
|
});
|
|
56
79
|
}
|
|
57
80
|
setListUploadFiles([]);
|
|
@@ -64,14 +87,27 @@ const MessageFooterProvider = ({ currentSession, openCreateCannedModal, }) => {
|
|
|
64
87
|
setCannedQuery(query);
|
|
65
88
|
openCanned();
|
|
66
89
|
}, [openCanned]);
|
|
90
|
+
const setIsOpenCanned = useCallback((open) => {
|
|
91
|
+
if (open) {
|
|
92
|
+
openCanned();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
closeCanned();
|
|
96
|
+
}, [closeCanned, openCanned]);
|
|
67
97
|
return (_jsx(MessageFooterContext.Provider, { value: {
|
|
68
98
|
onSendMessage,
|
|
99
|
+
isInternal,
|
|
100
|
+
setIsInternal,
|
|
69
101
|
listUploadFiles,
|
|
70
102
|
setListUploadFiles,
|
|
71
103
|
isOpenCanned,
|
|
72
|
-
setIsOpenCanned
|
|
104
|
+
setIsOpenCanned,
|
|
105
|
+
activeCannedIndex,
|
|
106
|
+
setActiveCannedIndex,
|
|
107
|
+
maxActiveCannedIndex,
|
|
108
|
+
setMaxActiveCannedIndex,
|
|
73
109
|
}, children: _jsxs(LexicalComposer, { initialConfig: initialConfig, children: [_jsx(Popover, { open: isOpenCanned, content: _jsx(CannedResponse, { onClose: closeCanned, openCreateCannedModal: onOpenCreateCannedModal, cannedQuery: cannedQuery }), placement: "topLeft", trigger: "click", arrow: false, classNames: {
|
|
74
110
|
body: "mx-1 !p-0",
|
|
75
|
-
}, destroyOnHidden: true, children: _jsxs("div", { className: "border-t pb-2 flex flex-col gap-1 bg-white", children: [_jsx(QuotedMessageFooter, {}), listUploadFiles.length > 0 && _jsx(FilePreview, {}), _jsx(ToolbarPlugin, {}),
|
|
111
|
+
}, destroyOnHidden: true, children: _jsxs("div", { className: "border-t pb-2 flex flex-col gap-1 bg-white", children: [_jsx(QuotedMessageFooter, {}), listUploadFiles.length > 0 && _jsx(FilePreview, {}), _jsx(ToolbarPlugin, {}), _jsxs("div", { children: [_jsx(ComposerTabs, { canUseInternal: canUseInternal, hintText: t("canned_response_hint"), isInternal: isInternal, setIsInternal: setIsInternal }), _jsx(ComposerEditor, { isInternal: isInternal, placeholderText: placeholderText })] }), _jsx(ActionBar, {})] }) }), _jsx(LinkPlugin, {}), _jsx(ListPlugin, {}), _jsx(EnterHandler, {}), _jsx(PasteAndDropPlugin, {}), isCrm && (_jsx(CannedResponseTriggerPlugin, { onClose: closeCanned, onOpen: onOpenCanned }))] }) }));
|
|
76
112
|
};
|
|
77
113
|
export default MessageFooterProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,IAAI,eAAe,EAG/B,MAAM,yBAAyB,CAAC;AA2BjC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED,QAAA,MAAM,WAAW,GAAI,2HAQlB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,IAAI,eAAe,EAG/B,MAAM,yBAAyB,CAAC;AA2BjC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED,QAAA,MAAM,WAAW,GAAI,2HAQlB,gBAAgB,mDAsQlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -102,6 +102,7 @@ const MessageItem = ({ message, allMessages, contextMenuOpen, onContextMenuOpenC
|
|
|
102
102
|
console.log("Failed to parse conversationData.ex");
|
|
103
103
|
}
|
|
104
104
|
}, [conversationData === null || conversationData === void 0 ? void 0 : conversationData.ex, isCrm, isMine]);
|
|
105
|
+
const isInternalMessage = Boolean(message === null || message === void 0 ? void 0 : message.isInternal);
|
|
105
106
|
const hasContextMenu = contextMenuItems.length > 0;
|
|
106
107
|
const isLatestMine = ((_a = allMessages.find((m) => m.sendID === userID)) === null || _a === void 0 ? void 0 : _a.clientMsgID) ===
|
|
107
108
|
message.clientMsgID;
|
|
@@ -114,6 +115,9 @@ const MessageItem = ({ message, allMessages, contextMenuOpen, onContextMenuOpenC
|
|
|
114
115
|
const showTimeBreak = prevTimeBreak;
|
|
115
116
|
const showSenderAvatar = !nextSameUser;
|
|
116
117
|
const showSenderName = !prevSameUser && !isMine;
|
|
118
|
+
if (!isCrm && isInternalMessage) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
117
121
|
if (!isCrm &&
|
|
118
122
|
(MessageType.CustomMessage === (message === null || message === void 0 ? void 0 : message.contentType) ||
|
|
119
123
|
!visibleTypeMessage.includes(message === null || message === void 0 ? void 0 : message.contentType))) {
|
|
@@ -121,7 +125,13 @@ const MessageItem = ({ message, allMessages, contextMenuOpen, onContextMenuOpenC
|
|
|
121
125
|
}
|
|
122
126
|
return (_jsxs("div", { className: "flex flex-col gap-2 py-1 px-3 sm:px-4 min-w-0", id: `${MSG_ITEM_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`, children: [showTimeBreak && (_jsx("div", { className: "flex justify-center", children: _jsx("span", { className: "text-xs text-gray-600 text-center bg-neutral-100 px-2 py-1 rounded-full", children: formatTimestamp(message.sendTime, {
|
|
123
127
|
dateMonthFormat: "DD MMMM",
|
|
124
|
-
}) }) })), _jsx("div", { className: clsx("flex min-w-0", isMine ? "justify-end" : "justify-start"), children: _jsxs("div", { className: clsx("flex flex-1 items-end gap-2 min-w-0", isMine ? "justify-end" : "justify-start"), children: [showSenderInfo && (_jsx("div", { className: "flex items-center justify-center w-[32px] h-[32px]", children: showSenderAvatar && (_jsx(Avatar, { src: message === null || message === void 0 ? void 0 : message.senderFaceUrl, children: ((_c = (_b = message === null || message === void 0 ? void 0 : message.senderNickname) === null || _b === void 0 ? void 0 : _b.charAt) === null || _c === void 0 ? void 0 : _c.call(_b, 0)) || "A" })) })), _jsxs("div", { className: clsx("flex flex-col max-w-[75%] min-w-0", isMine ? "items-end" : "items-start"), children: [showSenderName && showSenderInfo && (_jsx("span", { className: "text-xs font-bold mb-1 px-3 mt-2", children: message === null || message === void 0 ? void 0 : message.senderNickname })), _jsxs("div", { className: clsx("flex flex-col flex-1 w-full", isMine ? "items-end" : "items-start"), children: [(message === null || message === void 0 ? void 0 : message.quoteElem) && (_jsx(QuoteMessageItem, { message: message, isMine: isMine, onPressQuoteMessage: onPressQuoteMessage })), _jsxs("div", { className: "flex items-end gap-1.5", children: [isMine && (_jsx(MessageStatusIndicator, { message: message, isLatest: isLatestMine })), _jsx(Dropdown, { menu: { items: contextMenuItems }, trigger: hasContextMenu ? ["contextMenu"] : [], open: contextMenuOpen, onOpenChange: onContextMenuOpenChange, children: _jsxs("div", { className: clsx("px-3 py-2 rounded-2xl max-w-full min-w-0 break-normal flex flex-col flex-1 text-gray-900 gap-1 w-fit", isMine
|
|
128
|
+
}) }) })), _jsx("div", { className: clsx("flex min-w-0", isMine ? "justify-end" : "justify-start"), children: _jsxs("div", { className: clsx("flex flex-1 items-end gap-2 min-w-0", isMine ? "justify-end" : "justify-start"), children: [showSenderInfo && (_jsx("div", { className: "flex items-center justify-center w-[32px] h-[32px]", children: showSenderAvatar && (_jsx(Avatar, { src: message === null || message === void 0 ? void 0 : message.senderFaceUrl, children: ((_c = (_b = message === null || message === void 0 ? void 0 : message.senderNickname) === null || _b === void 0 ? void 0 : _b.charAt) === null || _c === void 0 ? void 0 : _c.call(_b, 0)) || "A" })) })), _jsxs("div", { className: clsx("flex flex-col max-w-[75%] min-w-0", isMine ? "items-end" : "items-start"), children: [showSenderName && showSenderInfo && (_jsx("span", { className: "text-xs font-bold mb-1 px-3 mt-2", children: message === null || message === void 0 ? void 0 : message.senderNickname })), _jsxs("div", { className: clsx("flex flex-col flex-1 w-full", isMine ? "items-end" : "items-start"), children: [(message === null || message === void 0 ? void 0 : message.quoteElem) && (_jsx(QuoteMessageItem, { message: message, isMine: isMine, onPressQuoteMessage: onPressQuoteMessage })), _jsxs("div", { className: "flex items-end gap-1.5", children: [isMine && (_jsx(MessageStatusIndicator, { message: message, isLatest: isLatestMine })), _jsx(Dropdown, { menu: { items: contextMenuItems }, trigger: hasContextMenu ? ["contextMenu"] : [], open: contextMenuOpen, onOpenChange: onContextMenuOpenChange, children: _jsxs("div", { className: clsx("px-3 py-2 rounded-2xl max-w-full min-w-0 break-normal flex flex-col flex-1 text-gray-900 gap-1 w-fit", isMine
|
|
129
|
+
? isInternalMessage
|
|
130
|
+
? "bg-orange-100"
|
|
131
|
+
: "bg-blue-100"
|
|
132
|
+
: isInternalMessage
|
|
133
|
+
? "bg-orange-100"
|
|
134
|
+
: "bg-white"), style: {
|
|
125
135
|
wordBreak: "break-word",
|
|
126
136
|
overflowWrap: "anywhere",
|
|
127
137
|
}, id: `${MSG_ITEM_CONTENT_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`, children: [(message === null || message === void 0 ? void 0 : message.contentType) === MessageType.MergeMessage ? (_jsxs("div", { children: [(_e = (_d = message === null || message === void 0 ? void 0 : message.mergeElem) === null || _d === void 0 ? void 0 : _d.multiMessage) === null || _e === void 0 ? void 0 : _e.map((item) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeskAssignedSession.d.ts","sourceRoot":"","sources":["../../../src/components/session/DeskAssignedSession.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DeskAssignedSession.d.ts","sourceRoot":"","sources":["../../../src/components/session/DeskAssignedSession.tsx"],"names":[],"mappings":"AAeA,QAAA,MAAM,mBAAmB,+CA2ExB,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -1,128 +1,33 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useBoolean } from "ahooks";
|
|
4
|
-
import { Button, Layout
|
|
5
|
-
import {
|
|
4
|
+
import { Button, Layout } from "antd";
|
|
5
|
+
import { useCallback, useEffect } from "react";
|
|
6
6
|
import { useTranslation } from "react-i18next";
|
|
7
7
|
import { Icon } from "../icon";
|
|
8
8
|
import { useGetSessionSummary } from "../../hooks/session/useGetSessionSummary";
|
|
9
9
|
import useSessionStore from "../../store/session";
|
|
10
|
-
import clsx from "clsx";
|
|
11
|
-
import { SessionStatus, SessionTag } from "../../types/chat";
|
|
12
10
|
import emitter from "../../utils/events";
|
|
11
|
+
import DeskTeamInbox from "./DeskTeamInbox";
|
|
12
|
+
import SessionFilterMenu from "./SessionFilterMenu";
|
|
13
13
|
const { Sider } = Layout;
|
|
14
14
|
const DeskAssignedSession = () => {
|
|
15
15
|
const { t } = useTranslation();
|
|
16
16
|
const [collapsed, { toggle }] = useBoolean(false);
|
|
17
17
|
const setFilterSummary = useSessionStore((state) => state.setFilterSummary);
|
|
18
|
+
const filterSummary = useSessionStore((state) => state.filterSummary);
|
|
18
19
|
const { data: sessionSummary, refetch } = useGetSessionSummary();
|
|
19
|
-
const
|
|
20
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
21
|
-
return [
|
|
22
|
-
{
|
|
23
|
-
label: t("active_sessions"),
|
|
24
|
-
key: "ACTIVE_SESSIONS",
|
|
25
|
-
icon: _jsx(Icon, { icon: "chat-dot-o", size: 20 }),
|
|
26
|
-
children: [
|
|
27
|
-
{
|
|
28
|
-
label: t("unassigned"),
|
|
29
|
-
key: SessionStatus.UNASSIGNED,
|
|
30
|
-
icon: (_jsx(Icon, { icon: "user-del-o", size: 18, className: "!text-amber-500" })),
|
|
31
|
-
onClick: () => {
|
|
32
|
-
setFilterSummary({
|
|
33
|
-
status: SessionStatus.UNASSIGNED,
|
|
34
|
-
tag: undefined,
|
|
35
|
-
});
|
|
36
|
-
},
|
|
37
|
-
itemIcon: !collapsed && (_jsx("span", { className: "text-xs text-gray-500 ", children: ((_b = (_a = sessionSummary === null || sessionSummary === void 0 ? void 0 : sessionSummary.sessionStatuses) === null || _a === void 0 ? void 0 : _a.find((s) => s.type === SessionStatus.UNASSIGNED)) === null || _b === void 0 ? void 0 : _b.count) || "" })),
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
label: t("slow_processing"),
|
|
41
|
-
key: SessionTag.SLOW_PROCESSING,
|
|
42
|
-
icon: (_jsx(Icon, { icon: "warning-square-o", size: 18, className: "!text-red-500" })),
|
|
43
|
-
onClick: () => {
|
|
44
|
-
setFilterSummary({
|
|
45
|
-
status: undefined,
|
|
46
|
-
tag: SessionTag.SLOW_PROCESSING,
|
|
47
|
-
});
|
|
48
|
-
},
|
|
49
|
-
itemIcon: !collapsed && (_jsx("span", { className: "text-xs text-gray-500", children: ((_d = (_c = sessionSummary === null || sessionSummary === void 0 ? void 0 : sessionSummary.tagCounts) === null || _c === void 0 ? void 0 : _c.find((s) => s.type === SessionTag.SLOW_PROCESSING)) === null || _d === void 0 ? void 0 : _d.count) || "" })),
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
label: t("waiting_process"),
|
|
53
|
-
key: SessionStatus.WAITING_PROCESS,
|
|
54
|
-
icon: (_jsx(Icon, { icon: "time-circle-o", size: 18, className: "!text-orange-400" })),
|
|
55
|
-
onClick: () => {
|
|
56
|
-
setFilterSummary({
|
|
57
|
-
status: SessionStatus.WAITING_PROCESS,
|
|
58
|
-
tag: undefined,
|
|
59
|
-
});
|
|
60
|
-
},
|
|
61
|
-
itemIcon: !collapsed && (_jsx("span", { className: "text-xs text-gray-500", children: ((_f = (_e = sessionSummary === null || sessionSummary === void 0 ? void 0 : sessionSummary.sessionStatuses) === null || _e === void 0 ? void 0 : _e.find((s) => s.type === SessionStatus.WAITING_PROCESS)) === null || _f === void 0 ? void 0 : _f.count) || "" })),
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
label: t("awaiting_reply"),
|
|
65
|
-
key: SessionTag.AWAITING_REPLY,
|
|
66
|
-
icon: (_jsx(Icon, { icon: "arrow-reply-o", size: 18, className: "!text-purple-500" })),
|
|
67
|
-
onClick: () => {
|
|
68
|
-
setFilterSummary({
|
|
69
|
-
status: undefined,
|
|
70
|
-
tag: SessionTag.AWAITING_REPLY,
|
|
71
|
-
});
|
|
72
|
-
},
|
|
73
|
-
itemIcon: !collapsed && (_jsx("span", { className: "text-xs text-gray-500", children: ((_h = (_g = sessionSummary === null || sessionSummary === void 0 ? void 0 : sessionSummary.tagCounts) === null || _g === void 0 ? void 0 : _g.find((s) => s.type === SessionTag.AWAITING_REPLY)) === null || _h === void 0 ? void 0 : _h.count) || "" })),
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
label: t("in_process"),
|
|
77
|
-
key: SessionStatus.IN_PROCESS,
|
|
78
|
-
icon: _jsx(Icon, { icon: "play-circle-o", size: 18 }),
|
|
79
|
-
onClick: () => {
|
|
80
|
-
setFilterSummary({
|
|
81
|
-
status: SessionStatus.IN_PROCESS,
|
|
82
|
-
tag: undefined,
|
|
83
|
-
});
|
|
84
|
-
},
|
|
85
|
-
itemIcon: !collapsed && (_jsx("span", { className: "text-xs text-gray-500", children: ((_k = (_j = sessionSummary === null || sessionSummary === void 0 ? void 0 : sessionSummary.sessionStatuses) === null || _j === void 0 ? void 0 : _j.find((s) => s.type === SessionStatus.IN_PROCESS)) === null || _k === void 0 ? void 0 : _k.count) || "" })),
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
label: t("temporarily_paused"),
|
|
89
|
-
key: SessionTag.TEMPORARILY_PAUSED,
|
|
90
|
-
icon: _jsx(Icon, { icon: "pause-o", size: 18 }),
|
|
91
|
-
onClick: () => {
|
|
92
|
-
setFilterSummary({
|
|
93
|
-
status: undefined,
|
|
94
|
-
tag: SessionTag.TEMPORARILY_PAUSED,
|
|
95
|
-
});
|
|
96
|
-
},
|
|
97
|
-
itemIcon: !collapsed && (_jsx("span", { className: "text-xs text-gray-500", children: ((_m = (_l = sessionSummary === null || sessionSummary === void 0 ? void 0 : sessionSummary.tagCounts) === null || _l === void 0 ? void 0 : _l.find((s) => s.type === SessionTag.TEMPORARILY_PAUSED)) === null || _m === void 0 ? void 0 : _m.count) || "" })),
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
itemIcon: !collapsed && (_jsx("span", { className: "text-xs text-gray-500", children: ((_p = (_o = sessionSummary === null || sessionSummary === void 0 ? void 0 : sessionSummary.sessionStatuses) === null || _o === void 0 ? void 0 : _o.find((s) => s.type === SessionStatus.IN_PROCESS)) === null || _p === void 0 ? void 0 : _p.count) || "" })),
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
label: t("closed_sessions"),
|
|
104
|
-
key: "CLOSED_SESSIONS",
|
|
105
|
-
icon: _jsx(Icon, { icon: "check-square-o", size: 20 }),
|
|
106
|
-
onClick: () => {
|
|
107
|
-
setFilterSummary({
|
|
108
|
-
status: SessionStatus.COMPLETED,
|
|
109
|
-
tag: undefined,
|
|
110
|
-
});
|
|
111
|
-
},
|
|
112
|
-
itemIcon: !collapsed && (_jsx("span", { className: "text-xs text-gray-500", children: (sessionSummary === null || sessionSummary === void 0 ? void 0 : sessionSummary.completedSessionCount) || "" })),
|
|
113
|
-
},
|
|
114
|
-
];
|
|
115
|
-
}, [sessionSummary, t, collapsed]);
|
|
20
|
+
const onFilterSelect = useCallback((filter) => setFilterSummary(filter), [setFilterSummary]);
|
|
116
21
|
useEffect(() => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
});
|
|
22
|
+
const handler = () => refetch();
|
|
23
|
+
emitter.on("UPDATE_SESSION", handler);
|
|
120
24
|
return () => {
|
|
121
|
-
emitter.off("UPDATE_SESSION",
|
|
122
|
-
refetch();
|
|
123
|
-
});
|
|
25
|
+
emitter.off("UPDATE_SESSION", handler);
|
|
124
26
|
};
|
|
125
|
-
}, []);
|
|
126
|
-
|
|
27
|
+
}, [refetch]);
|
|
28
|
+
if (collapsed) {
|
|
29
|
+
return (_jsx("div", { className: "flex flex-col items-center pt-4 border-r border-gray-200 bg-white", children: _jsx(Button, { type: "text", shape: "circle", className: "text-gray-500 w-8 h-8 p-0", onClick: toggle, children: _jsx(Icon, { icon: "angle-right-o", size: 22 }) }) }));
|
|
30
|
+
}
|
|
31
|
+
return (_jsx(Sider, { collapsible: true, collapsed: false, width: 220, className: "bg-white h-full border-r border-gray-200", trigger: null, children: _jsxs("div", { className: "flex flex-col h-full", children: [_jsxs("div", { className: "flex items-center justify-between p-4 border-b shrink-0", children: [_jsx("span", { className: "text-md font-semibold flex-1 truncate", children: "Droppii Livechat" }), _jsx(Button, { type: "text", className: "text-gray-500 w-8 h-8 p-0", onClick: toggle, children: _jsx(Icon, { icon: "angle-left-o", size: 22 }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto min-h-0", children: [_jsx("div", { className: "px-4 pt-4 pb-2 text-xs font-semibold text-gray-400 tracking-wider", children: t("my_messages") }), sessionSummary && (_jsx(SessionFilterMenu, { summary: sessionSummary, isActive: !filterSummary.teamId, filterSummary: filterSummary, onFilterSelect: onFilterSelect, activeCount: sessionSummary.activeSessionCount })), _jsx(DeskTeamInbox, {})] })] }) }));
|
|
127
32
|
};
|
|
128
33
|
export default DeskAssignedSession;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeskTeamInbox.d.ts","sourceRoot":"","sources":["../../../src/components/session/DeskTeamInbox.tsx"],"names":[],"mappings":"AAuDA,QAAA,MAAM,aAAa,sDAyElB,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
import { Icon } from "../icon";
|
|
6
|
+
import { useGetTeamSessionSummary } from "../../hooks/session/useGetTeamSessionSummary";
|
|
7
|
+
import useSessionStore from "../../store/session";
|
|
8
|
+
import emitter from "../../utils/events";
|
|
9
|
+
import SessionFilterMenu from "./SessionFilterMenu";
|
|
10
|
+
const TeamGroup = memo(({ team, isExpanded, isSelected, selectedFilter, onToggle, onFilterSelect, }) => (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-2 cursor-pointer hover:bg-gray-50", onClick: onToggle, children: [_jsx("span", { className: "text-sm font-semibold text-blue-500 truncate flex-1", children: team.teamName }), _jsx(Icon, { icon: isExpanded ? "angle-up-o" : "angle-down-o", size: 16, className: "text-gray-400 shrink-0" })] }), isExpanded && (_jsx(SessionFilterMenu, { summary: team.summary, isActive: isSelected, filterSummary: selectedFilter, onFilterSelect: onFilterSelect, includeUnassigned: true, activeCount: team.summary.activeSessionCount }))] })));
|
|
11
|
+
const DeskTeamInbox = () => {
|
|
12
|
+
const { t } = useTranslation();
|
|
13
|
+
const { data: teamSummaries, refetch } = useGetTeamSessionSummary();
|
|
14
|
+
const filterSummary = useSessionStore((s) => s.filterSummary);
|
|
15
|
+
const setFilterSummary = useSessionStore((s) => s.setFilterSummary);
|
|
16
|
+
const [expandedTeamIds, setExpandedTeamIds] = useState([]);
|
|
17
|
+
const initializedRef = useRef(false);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if ((teamSummaries === null || teamSummaries === void 0 ? void 0 : teamSummaries.length) && !initializedRef.current) {
|
|
20
|
+
setExpandedTeamIds([teamSummaries[0].teamId]);
|
|
21
|
+
initializedRef.current = true;
|
|
22
|
+
}
|
|
23
|
+
}, [teamSummaries]);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const handler = () => refetch();
|
|
26
|
+
emitter.on("UPDATE_SESSION", handler);
|
|
27
|
+
return () => {
|
|
28
|
+
emitter.off("UPDATE_SESSION", handler);
|
|
29
|
+
};
|
|
30
|
+
}, [refetch]);
|
|
31
|
+
const toggleTeam = useCallback((teamId) => {
|
|
32
|
+
setExpandedTeamIds((prev) => prev.includes(teamId)
|
|
33
|
+
? prev.filter((id) => id !== teamId)
|
|
34
|
+
: [...prev, teamId]);
|
|
35
|
+
}, []);
|
|
36
|
+
const toggleHandlers = useMemo(() => {
|
|
37
|
+
if (!teamSummaries)
|
|
38
|
+
return {};
|
|
39
|
+
return Object.fromEntries(teamSummaries.map((team) => [
|
|
40
|
+
team.teamId,
|
|
41
|
+
() => toggleTeam(team.teamId),
|
|
42
|
+
]));
|
|
43
|
+
}, [teamSummaries, toggleTeam]);
|
|
44
|
+
const filterHandlers = useMemo(() => {
|
|
45
|
+
if (!teamSummaries)
|
|
46
|
+
return {};
|
|
47
|
+
return Object.fromEntries(teamSummaries.map((team) => [
|
|
48
|
+
team.teamId,
|
|
49
|
+
(filter) => setFilterSummary(Object.assign(Object.assign({}, filter), { teamId: team.teamId })),
|
|
50
|
+
]));
|
|
51
|
+
}, [teamSummaries, setFilterSummary]);
|
|
52
|
+
if (!(teamSummaries === null || teamSummaries === void 0 ? void 0 : teamSummaries.length))
|
|
53
|
+
return null;
|
|
54
|
+
return (_jsxs("div", { children: [_jsx("div", { className: "px-4 pt-4 pb-2 text-xs font-semibold text-gray-400 tracking-wider", children: t("team_messages") }), teamSummaries.map((team) => (_jsx(TeamGroup, { team: team, isExpanded: expandedTeamIds.includes(team.teamId), isSelected: filterSummary.teamId === team.teamId, selectedFilter: filterSummary, onToggle: toggleHandlers[team.teamId], onFilterSelect: filterHandlers[team.teamId] }, team.teamId)))] }));
|
|
55
|
+
};
|
|
56
|
+
export default DeskTeamInbox;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { IFilterSummary } from "../../store/type";
|
|
2
|
+
import { ISessionSummaryResponse } from "../../types/dto";
|
|
3
|
+
interface SessionFilterMenuProps {
|
|
4
|
+
summary: ISessionSummaryResponse;
|
|
5
|
+
isActive: boolean;
|
|
6
|
+
filterSummary: IFilterSummary;
|
|
7
|
+
onFilterSelect: (filter: IFilterSummary) => void;
|
|
8
|
+
includeUnassigned?: boolean;
|
|
9
|
+
activeCount?: number;
|
|
10
|
+
}
|
|
11
|
+
declare const SessionFilterMenu: ({ summary, isActive, filterSummary, onFilterSelect, includeUnassigned, activeCount, }: SessionFilterMenuProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export default SessionFilterMenu;
|
|
13
|
+
//# sourceMappingURL=SessionFilterMenu.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionFilterMenu.d.ts","sourceRoot":"","sources":["../../../src/components/session/SessionFilterMenu.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAG1D,UAAU,sBAAsB;IAC9B,OAAO,EAAE,uBAAuB,CAAC;IACjC,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,cAAc,CAAC;IAC9B,cAAc,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IACjD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAaD,QAAA,MAAM,iBAAiB,GAAI,uFAOxB,sBAAsB,4CAiCxB,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
import { Menu } from "antd";
|
|
6
|
+
import { SessionStatus } from "../../types/chat";
|
|
7
|
+
import { buildSessionMenuItems } from "./sessionMenuItems";
|
|
8
|
+
const getSelectedKeys = (isActive, filterSummary) => {
|
|
9
|
+
if (!isActive)
|
|
10
|
+
return [];
|
|
11
|
+
if (filterSummary.status === SessionStatus.COMPLETED)
|
|
12
|
+
return [SessionStatus.COMPLETED];
|
|
13
|
+
const key = filterSummary.status || filterSummary.tag;
|
|
14
|
+
return key ? [key] : [];
|
|
15
|
+
};
|
|
16
|
+
const SessionFilterMenu = ({ summary, isActive, filterSummary, onFilterSelect, includeUnassigned = false, activeCount, }) => {
|
|
17
|
+
const { t } = useTranslation();
|
|
18
|
+
const selectedKeys = useMemo(() => getSelectedKeys(isActive, filterSummary), [isActive, filterSummary]);
|
|
19
|
+
const menuItems = useMemo(() => buildSessionMenuItems({
|
|
20
|
+
summary,
|
|
21
|
+
t,
|
|
22
|
+
onFilterSelect,
|
|
23
|
+
includeUnassigned,
|
|
24
|
+
}), [summary, t, onFilterSelect, includeUnassigned]);
|
|
25
|
+
return (_jsx(Menu, { selectedKeys: selectedKeys, defaultOpenKeys: ["ACTIVE_SESSIONS"], mode: "inline", items: menuItems, inlineIndent: 12, expandIcon: activeCount ? (_jsx("span", { className: "text-xs", children: activeCount })) : undefined }));
|
|
26
|
+
};
|
|
27
|
+
export default SessionFilterMenu;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { MenuProps } from "antd";
|
|
2
|
+
import { TFunction } from "i18next";
|
|
3
|
+
import { IFilterSummary } from "../../store/type";
|
|
4
|
+
import { ISessionSummaryResponse } from "../../types/dto";
|
|
5
|
+
type MenuItem = Required<MenuProps>["items"][number];
|
|
6
|
+
interface SessionFilterConfig {
|
|
7
|
+
key: string;
|
|
8
|
+
labelKey: string;
|
|
9
|
+
iconName: string;
|
|
10
|
+
iconClassName?: string;
|
|
11
|
+
filter: IFilterSummary;
|
|
12
|
+
countSource: "status" | "tag";
|
|
13
|
+
teamOnly?: boolean;
|
|
14
|
+
highlighted?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare const SESSION_FILTER_CONFIGS: SessionFilterConfig[];
|
|
17
|
+
export declare const getFilterConfig: (key: string) => SessionFilterConfig | undefined;
|
|
18
|
+
interface BuildSessionMenuItemsOptions {
|
|
19
|
+
summary: ISessionSummaryResponse;
|
|
20
|
+
t: TFunction;
|
|
21
|
+
onFilterSelect: (filter: IFilterSummary) => void;
|
|
22
|
+
includeUnassigned?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare const buildSessionMenuItems: ({ summary, t, onFilterSelect, includeUnassigned, }: BuildSessionMenuItemsOptions) => MenuItem[];
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=sessionMenuItems.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionMenuItems.d.ts","sourceRoot":"","sources":["../../../src/components/session/sessionMenuItems.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGpC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,KAAK,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,UAAU,mBAAmB;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,WAAW,EAAE,QAAQ,GAAG,KAAK,CAAC;IAC9B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,eAAO,MAAM,sBAAsB,EAAE,mBAAmB,EA0DvD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,oCACQ,CAAC;AAEpD,UAAU,4BAA4B;IACpC,OAAO,EAAE,uBAAuB,CAAC;IACjC,CAAC,EAAE,SAAS,CAAC;IACb,cAAc,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IACjD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AA0BD,eAAO,MAAM,qBAAqB,GAAI,oDAKnC,4BAA4B,KAAG,QAAQ,EA4CzC,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Icon } from "../icon";
|
|
3
|
+
import { SessionStatus, SessionTag } from "../../types/chat";
|
|
4
|
+
export const SESSION_FILTER_CONFIGS = [
|
|
5
|
+
{
|
|
6
|
+
key: SessionStatus.UNASSIGNED,
|
|
7
|
+
labelKey: "unassigned",
|
|
8
|
+
iconName: "user-del-o",
|
|
9
|
+
iconClassName: "!text-amber-500",
|
|
10
|
+
filter: { status: SessionStatus.UNASSIGNED, tag: undefined },
|
|
11
|
+
countSource: "status",
|
|
12
|
+
teamOnly: true,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
key: SessionTag.SLOW_PROCESSING,
|
|
16
|
+
labelKey: "slow_processing",
|
|
17
|
+
iconName: "warning-square-o",
|
|
18
|
+
iconClassName: "!text-red-500",
|
|
19
|
+
filter: { status: undefined, tag: SessionTag.SLOW_PROCESSING },
|
|
20
|
+
countSource: "tag",
|
|
21
|
+
highlighted: true,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
key: SessionStatus.WAITING_PROCESS,
|
|
25
|
+
labelKey: "waiting_process",
|
|
26
|
+
iconName: "time-circle-o",
|
|
27
|
+
iconClassName: "!text-orange-400",
|
|
28
|
+
filter: { status: SessionStatus.WAITING_PROCESS, tag: undefined },
|
|
29
|
+
countSource: "status",
|
|
30
|
+
highlighted: true,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
key: SessionTag.AWAITING_REPLY,
|
|
34
|
+
labelKey: "awaiting_reply",
|
|
35
|
+
iconName: "arrow-reply-o",
|
|
36
|
+
iconClassName: "!text-purple-500",
|
|
37
|
+
filter: { status: undefined, tag: SessionTag.AWAITING_REPLY },
|
|
38
|
+
countSource: "tag",
|
|
39
|
+
highlighted: true,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: SessionStatus.IN_PROCESS,
|
|
43
|
+
labelKey: "in_process",
|
|
44
|
+
iconName: "play-circle-o",
|
|
45
|
+
filter: { status: SessionStatus.IN_PROCESS, tag: undefined },
|
|
46
|
+
countSource: "status",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
key: SessionTag.TEMPORARILY_PAUSED,
|
|
50
|
+
labelKey: "temporarily_paused",
|
|
51
|
+
iconName: "pause-o",
|
|
52
|
+
filter: { status: undefined, tag: SessionTag.TEMPORARILY_PAUSED },
|
|
53
|
+
countSource: "tag",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
key: SessionStatus.COMPLETED,
|
|
57
|
+
labelKey: "closed_sessions",
|
|
58
|
+
iconName: "check-square-o",
|
|
59
|
+
filter: { status: SessionStatus.COMPLETED, tag: undefined },
|
|
60
|
+
countSource: "status",
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
export const getFilterConfig = (key) => SESSION_FILTER_CONFIGS.find((c) => c.key === key);
|
|
64
|
+
const countBadge = (count, highlighted) => {
|
|
65
|
+
if (!count)
|
|
66
|
+
return null;
|
|
67
|
+
if (highlighted) {
|
|
68
|
+
return (_jsx("span", { className: "text-xs font-medium text-white bg-red-500 rounded-full px-1.5 py-0.5 leading-none -mr-1.5", children: count }));
|
|
69
|
+
}
|
|
70
|
+
return _jsx("span", { className: "text-xs text-gray-500", children: count });
|
|
71
|
+
};
|
|
72
|
+
const getCount = (config, summary) => {
|
|
73
|
+
var _a, _b, _c, _d;
|
|
74
|
+
if (config.countSource === "status") {
|
|
75
|
+
return (((_b = (_a = summary.sessionStatuses) === null || _a === void 0 ? void 0 : _a.find((s) => s.type === config.key)) === null || _b === void 0 ? void 0 : _b.count) || "");
|
|
76
|
+
}
|
|
77
|
+
return ((_d = (_c = summary.tagCounts) === null || _c === void 0 ? void 0 : _c.find((s) => s.type === config.key)) === null || _d === void 0 ? void 0 : _d.count) || "";
|
|
78
|
+
};
|
|
79
|
+
export const buildSessionMenuItems = ({ summary, t, onFilterSelect, includeUnassigned = false, }) => {
|
|
80
|
+
const activeConfigs = SESSION_FILTER_CONFIGS.filter((c) => c.key !== SessionStatus.COMPLETED &&
|
|
81
|
+
(!c.teamOnly || includeUnassigned));
|
|
82
|
+
const activeChildren = activeConfigs.map((config) => ({
|
|
83
|
+
label: t(config.labelKey),
|
|
84
|
+
key: config.key,
|
|
85
|
+
icon: (_jsx(Icon, { icon: config.iconName, size: 18, className: config.iconClassName })),
|
|
86
|
+
onClick: () => onFilterSelect(config.filter),
|
|
87
|
+
itemIcon: countBadge(getCount(config, summary), config.highlighted),
|
|
88
|
+
}));
|
|
89
|
+
const closedConfig = SESSION_FILTER_CONFIGS.find((c) => c.key === SessionStatus.COMPLETED);
|
|
90
|
+
const closedItem = closedConfig
|
|
91
|
+
? {
|
|
92
|
+
label: t(closedConfig.labelKey),
|
|
93
|
+
key: closedConfig.key,
|
|
94
|
+
icon: _jsx(Icon, { icon: closedConfig.iconName, size: 20 }),
|
|
95
|
+
onClick: () => onFilterSelect(closedConfig.filter),
|
|
96
|
+
itemIcon: countBadge(summary.completedSessionCount),
|
|
97
|
+
}
|
|
98
|
+
: null;
|
|
99
|
+
return [
|
|
100
|
+
{
|
|
101
|
+
label: t("active_sessions"),
|
|
102
|
+
key: "ACTIVE_SESSIONS",
|
|
103
|
+
icon: _jsx(Icon, { icon: "chat-dot-o", size: 20 }),
|
|
104
|
+
children: activeChildren,
|
|
105
|
+
},
|
|
106
|
+
closedItem,
|
|
107
|
+
].filter(Boolean);
|
|
108
|
+
};
|