@droppii-org/chat-sdk 0.6.40 → 0.6.42
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/conversation-detail/ConversationDetailHeader.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationDetailHeader.js +2 -6
- package/dist/components/conversation-detail/ConversationMessageList.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationMessageList.js +7 -3
- package/dist/components/conversation-detail/PinnedMessageBar.d.ts +7 -1
- package/dist/components/conversation-detail/PinnedMessageBar.d.ts.map +1 -1
- package/dist/components/conversation-detail/PinnedMessageBar.js +4 -3
- package/dist/components/conversation-detail/PinnedMessageItem.d.ts +2 -1
- package/dist/components/conversation-detail/PinnedMessageItem.d.ts.map +1 -1
- package/dist/components/conversation-detail/PinnedMessageItem.js +9 -8
- package/dist/components/conversation-detail/PinnedMessagesPanel.d.ts +2 -1
- package/dist/components/conversation-detail/PinnedMessagesPanel.d.ts.map +1 -1
- package/dist/components/conversation-detail/PinnedMessagesPanel.js +2 -2
- package/dist/components/conversation-detail/ThreadProfilePanel.d.ts.map +1 -1
- package/dist/components/conversation-detail/ThreadProfilePanel.js +4 -7
- package/dist/components/message/MessageList.d.ts +2 -0
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +3 -2
- package/dist/components/message/item/index.d.ts.map +1 -1
- package/dist/components/message/item/index.js +6 -4
- package/dist/hooks/conversation/useConversationPeerIdentity.d.ts +15 -0
- package/dist/hooks/conversation/useConversationPeerIdentity.d.ts.map +1 -0
- package/dist/hooks/conversation/useConversationPeerIdentity.js +48 -0
- package/dist/hooks/message/useMessage.d.ts +2 -1
- package/dist/hooks/message/useMessage.d.ts.map +1 -1
- package/dist/hooks/message/useMessage.js +25 -11
- package/dist/hooks/message/usePinnedMessages.d.ts.map +1 -1
- package/dist/hooks/message/usePinnedMessages.js +6 -0
- package/dist/screens/desk-message/index.d.ts.map +1 -1
- package/dist/screens/desk-message/index.js +1 -1
- package/dist/utils/conversation.d.ts +12 -0
- package/dist/utils/conversation.d.ts.map +1 -1
- package/dist/utils/conversation.js +32 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationDetailHeader.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailHeader.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"ConversationDetailHeader.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailHeader.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGrE,MAAM,WAAW,6BAA6B;IAC5C,YAAY,EAAE,gBAAgB,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAsBD,QAAA,MAAM,wBAAwB,GAAI,2CAI/B,6BAA6B,4CAyC/B,CAAC;AAEF,eAAe,wBAAwB,CAAC"}
|
|
@@ -4,15 +4,11 @@ import { useTranslation } from "react-i18next";
|
|
|
4
4
|
import { Icon } from "../../components/icon";
|
|
5
5
|
import ConversationPeerAvatar from "../../components/conversation-inbox/ConversationPeerAvatar";
|
|
6
6
|
import ConversationInboxTitle from "../../components/conversation-inbox/ConversationInboxTitle";
|
|
7
|
-
import {
|
|
8
|
-
import { useConversationAvatarUrl } from "../../hooks/conversation/useConversationAvatarUrl";
|
|
7
|
+
import { useConversationPeerIdentity } from "../../hooks/conversation/useConversationPeerIdentity";
|
|
9
8
|
const HeaderIconButton = ({ icon, onClick, testId, }) => (_jsx("button", { type: "button", onClick: onClick, "data-testid": testId, "data-cp-name": "HeaderIconButton", className: "flex shrink-0 cursor-pointer items-center justify-center p-2 text-[var(--dc-color-nav-icon)]", children: _jsx(Icon, { icon: icon, size: 24 }) }));
|
|
10
9
|
const ConversationDetailHeader = ({ conversation, onBack, onProfileClick, }) => {
|
|
11
10
|
const { t } = useTranslation("conversation-inbox");
|
|
12
|
-
const displayName =
|
|
13
|
-
const avatarUrl = useConversationAvatarUrl(conversation);
|
|
14
|
-
const peerType = conversation.peerType;
|
|
15
|
-
const badgeLabel = resolvePeerBadgeLabel(peerType, t);
|
|
11
|
+
const { displayName, avatarUrl, peerType, badgeLabel } = useConversationPeerIdentity(conversation);
|
|
16
12
|
const subtitle = t("thread_detail.profile_hint");
|
|
17
13
|
return (_jsxs("div", { "data-testid": "conversation-detail-header", "data-cp-name": "ConversationDetailHeader", className: "flex w-full cursor-default items-center border-b border-gray-25 bg-white p-2 shadow-inset-gray-divider", children: [_jsx(HeaderIconButton, { icon: "arrow-left-o", onClick: onBack, testId: "conversation-detail-back" }), _jsxs("div", { className: "flex min-w-0 flex-1 cursor-pointer items-center gap-2 px-1", "data-testid": "conversation-detail-profile", onClick: onProfileClick, children: [_jsx(ConversationPeerAvatar, { peerType: peerType, displayName: displayName, avatarUrl: avatarUrl, badgeLabel: badgeLabel }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(ConversationInboxTitle, { peerType: peerType, displayName: displayName }), _jsx("p", { className: "truncate text-[10px] font-normal leading-[160%] tracking-[0.1px] text-gray-600 [font-feature-settings:'liga'_off,'clig'_off]", children: subtitle })] })] })] }));
|
|
18
14
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationMessageList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ConversationMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationMessageList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAsBzE,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,uBAAuB,GAAI,4DAI9B,4BAA4B,4CAsO9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -13,7 +13,7 @@ import { useRevokeMessage } from "../../hooks/message/useRevokeMessage";
|
|
|
13
13
|
import { useGroupPermission } from "../../hooks/group/useGroupPermission";
|
|
14
14
|
import useConversationStore from "../../store/conversation";
|
|
15
15
|
import useAuthStore from "../../store/auth";
|
|
16
|
-
import { isGroupChat as resolveIsGroupChat } from "../../utils/conversation";
|
|
16
|
+
import { isGroupChat as resolveIsGroupChat, isSupportSessionAgentView, } from "../../utils/conversation";
|
|
17
17
|
import emitter from "../../utils/events";
|
|
18
18
|
import MessageItem from "../../components/message/item";
|
|
19
19
|
import PinLimitModal from "./PinLimitModal";
|
|
@@ -33,8 +33,12 @@ const ConversationMessageList = ({ bottomSlot, onCopyMessageLink, onSearchMessag
|
|
|
33
33
|
// Some hosts run pin without their backend returning PIN_MESSAGE yet, so
|
|
34
34
|
// the permission check would hide a feature that is live for them.
|
|
35
35
|
const canPinMessage = !isGroupChat || permissions.pinMessage || allowPinMessageWithoutPermission;
|
|
36
|
-
const
|
|
37
|
-
|
|
36
|
+
const viewerUserID = (user === null || user === void 0 ? void 0 : user.userID) || authUserID;
|
|
37
|
+
// App history strips the assignment log and session dividers, which an
|
|
38
|
+
// agent handling someone else's session needs — load the full history.
|
|
39
|
+
const useAppHistory = !isSupportSessionAgentView(Object.assign(Object.assign({}, conversation), { conversationID: conversationId }), viewerUserID);
|
|
40
|
+
const messageController = useMessage(conversationId, searchClientMsgID, true, useAppHistory, onSearchMessageRevoked);
|
|
41
|
+
const { scrollRef, loadMoreOldMessage, handleInfiniteScroll, scrollToBottomIfAtBottom, scrollToMessage, } = useMessageListScroll(Object.assign({ conversationId, userId: viewerUserID, isGroupChat }, messageController));
|
|
38
42
|
const { loadState, moreOldLoading } = messageController;
|
|
39
43
|
const isMessageLoading = !conversationId || loadState.initLoading;
|
|
40
44
|
const [openToolboxMessageId, setOpenToolboxMessageId] = useState(null);
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
interface PinnedMessageBarProps {
|
|
2
|
+
/** CRM spec labels every pin "Tin nhắn từ {name}"; BIZ varies the label by message type. */
|
|
3
|
+
genericSubtitle?: boolean;
|
|
4
|
+
/** Hides unpin in the pinned panel for users the toolbox already denies pinning. */
|
|
5
|
+
canUnpin?: boolean;
|
|
6
|
+
}
|
|
7
|
+
declare const PinnedMessageBar: ({ genericSubtitle, canUnpin, }: PinnedMessageBarProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
2
8
|
export default PinnedMessageBar;
|
|
3
9
|
//# sourceMappingURL=PinnedMessageBar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PinnedMessageBar.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/PinnedMessageBar.tsx"],"names":[],"mappings":"AA6HA,QAAA,MAAM,gBAAgB,
|
|
1
|
+
{"version":3,"file":"PinnedMessageBar.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/PinnedMessageBar.tsx"],"names":[],"mappings":"AA6HA,UAAU,qBAAqB;IAC7B,4FAA4F;IAC5F,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,oFAAoF;IACpF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,gBAAgB,GAAI,gCAGvB,qBAAqB,mDAkGvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -69,7 +69,7 @@ const PinnedMessageThumbnail = ({ message }) => {
|
|
|
69
69
|
}
|
|
70
70
|
return null;
|
|
71
71
|
};
|
|
72
|
-
const PinnedMessageBar = () => {
|
|
72
|
+
const PinnedMessageBar = ({ genericSubtitle = false, canUnpin = true, }) => {
|
|
73
73
|
const { t } = useTranslation();
|
|
74
74
|
const userID = useAuthStore((state) => state.userID);
|
|
75
75
|
const conversation = useConversationStore((state) => state.conversationData);
|
|
@@ -91,7 +91,8 @@ const PinnedMessageBar = () => {
|
|
|
91
91
|
? t("your_self")
|
|
92
92
|
: latestPinnedMessage.senderNickname || t("message_sender_unnamed");
|
|
93
93
|
const isRevoked = latestPinnedMessage.contentType === MessageType.RevokeMessage;
|
|
94
|
-
const subtitleKey =
|
|
94
|
+
const subtitleKey = (!genericSubtitle &&
|
|
95
|
+
PINNED_SUBTITLE_KEY_BY_TYPE[latestPinnedMessage.contentType]) ||
|
|
95
96
|
"pinned_from_text";
|
|
96
97
|
const title = isRevoked
|
|
97
98
|
? t("revoked")
|
|
@@ -104,6 +105,6 @@ const PinnedMessageBar = () => {
|
|
|
104
105
|
const hasFlushThumbnail = hasThumbnail &&
|
|
105
106
|
latestPinnedMessage.contentType !== MessageType.FileMessage;
|
|
106
107
|
const remainingPinnedCount = pinnedTotalCount - 1;
|
|
107
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { "data-testid": "pinned-message-bar", "data-cp-name": "PinnedMessageBar", role: "button", tabIndex: 0, onClick: () => setIsPanelOpen(true), className: clsx("flex w-full shrink-0 cursor-pointer items-center gap-3 bg-gray-cool-25 pr-3", hasFlushThumbnail ? "py-0 pl-0" : "py-1 pl-3"), children: [hasThumbnail && (_jsx(PinnedMessageThumbnail, { message: latestPinnedMessage })), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col justify-center", children: [showTitle && (_jsx("p", { className: "truncate text-sm font-medium leading-[160%] text-gray-900", children: title })), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Icon, { icon: "thumbtack-b", size: 12, className: "text-[var(--dc-color-primary)]" }), _jsx("p", { className: "truncate text-[13px] leading-[160%] text-gray-600", children: t(subtitleKey, { name: senderName }) })] })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [remainingPinnedCount > 0 && (_jsxs("span", { className: "flex min-w-[26px] items-center justify-center rounded-full border-2 border-white bg-gradient-danger-light px-1 text-xs font-bold leading-[160%] text-white", children: ["+", remainingPinnedCount] })), _jsx(Icon, { icon: "angle-down-o", size: 20, className: "text-gray-600" })] })] }), _jsx(PinnedMessagesPanel, { open: isPanelOpen, onClose: () => setIsPanelOpen(false) })] }));
|
|
108
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { "data-testid": "pinned-message-bar", "data-cp-name": "PinnedMessageBar", role: "button", tabIndex: 0, onClick: () => setIsPanelOpen(true), className: clsx("flex w-full shrink-0 cursor-pointer items-center gap-3 bg-gray-cool-25 pr-3", hasFlushThumbnail ? "py-0 pl-0" : "py-1 pl-3"), children: [hasThumbnail && (_jsx(PinnedMessageThumbnail, { message: latestPinnedMessage })), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col justify-center", children: [showTitle && (_jsx("p", { className: "truncate text-sm font-medium leading-[160%] text-gray-900", children: title })), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Icon, { icon: "thumbtack-b", size: 12, className: "text-[var(--dc-color-primary)]" }), _jsx("p", { className: "truncate text-[13px] leading-[160%] text-gray-600", children: t(subtitleKey, { name: senderName }) })] })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [remainingPinnedCount > 0 && (_jsxs("span", { className: "flex min-w-[26px] items-center justify-center rounded-full border-2 border-white bg-gradient-danger-light px-1 text-xs font-bold leading-[160%] text-white", children: ["+", remainingPinnedCount] })), _jsx(Icon, { icon: "angle-down-o", size: 20, className: "text-gray-600" })] })] }), _jsx(PinnedMessagesPanel, { open: isPanelOpen, onClose: () => setIsPanelOpen(false), canUnpin: canUnpin })] }));
|
|
108
109
|
};
|
|
109
110
|
export default PinnedMessageBar;
|
|
@@ -5,7 +5,8 @@ interface PinnedMessageItemProps {
|
|
|
5
5
|
onContextMenuOpenChange: (open: boolean) => void;
|
|
6
6
|
onUnpin: (message: MessageItemType) => void;
|
|
7
7
|
onJump: (message: MessageItemType) => void;
|
|
8
|
+
canUnpin?: boolean;
|
|
8
9
|
}
|
|
9
|
-
declare const PinnedMessageItem: ({ message, contextMenuOpen, onContextMenuOpenChange, onUnpin, onJump, }: PinnedMessageItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
declare const PinnedMessageItem: ({ message, contextMenuOpen, onContextMenuOpenChange, onUnpin, onJump, canUnpin, }: PinnedMessageItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
11
|
export default PinnedMessageItem;
|
|
11
12
|
//# sourceMappingURL=PinnedMessageItem.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PinnedMessageItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/PinnedMessageItem.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAY9E,UAAU,sBAAsB;IAC9B,OAAO,EAAE,eAAe,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,uBAAuB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC5C,MAAM,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"PinnedMessageItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/PinnedMessageItem.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAY9E,UAAU,sBAAsB;IAC9B,OAAO,EAAE,eAAe,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,uBAAuB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,OAAO,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC5C,MAAM,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,iBAAiB,GAAI,mFAOxB,sBAAsB,4CAqFxB,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -8,17 +8,18 @@ import MessageBubble from "../../components/message/item/MessageBubble";
|
|
|
8
8
|
import { renderBubbleContent } from "../../components/message/item/renderMessageContent";
|
|
9
9
|
import { buildMessageToolboxMenuItems, MessageToolboxActionKey, MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, } from "../../components/message/toolbox";
|
|
10
10
|
import useAuthStore from "../../store/auth";
|
|
11
|
-
const PinnedMessageItem = ({ message, contextMenuOpen, onContextMenuOpenChange, onUnpin, onJump, }) => {
|
|
11
|
+
const PinnedMessageItem = ({ message, contextMenuOpen, onContextMenuOpenChange, onUnpin, onJump, canUnpin = true, }) => {
|
|
12
12
|
const { t } = useTranslation();
|
|
13
13
|
const userID = useAuthStore((state) => state.userID);
|
|
14
14
|
const isMine = (message === null || message === void 0 ? void 0 : message.sendID) === userID;
|
|
15
|
+
const unpinAction = {
|
|
16
|
+
key: MessageToolboxActionKey.UNPIN,
|
|
17
|
+
label: t("context_menu_unpin"),
|
|
18
|
+
icon: "thumbtack-off-o",
|
|
19
|
+
onClick: () => onUnpin(message),
|
|
20
|
+
};
|
|
15
21
|
const contextMenuItems = buildMessageToolboxMenuItems([
|
|
16
|
-
|
|
17
|
-
key: MessageToolboxActionKey.UNPIN,
|
|
18
|
-
label: t("context_menu_unpin"),
|
|
19
|
-
icon: "thumbtack-off-o",
|
|
20
|
-
onClick: () => onUnpin(message),
|
|
21
|
-
},
|
|
22
|
+
...(canUnpin ? [unpinAction] : []),
|
|
22
23
|
{
|
|
23
24
|
key: MessageToolboxActionKey.VIEW_ORIGINAL,
|
|
24
25
|
label: t("context_menu_view_original"),
|
|
@@ -32,6 +33,6 @@ const PinnedMessageItem = ({ message, contextMenuOpen, onContextMenuOpenChange,
|
|
|
32
33
|
event.stopPropagation();
|
|
33
34
|
onUnpin(message);
|
|
34
35
|
}, className: "flex h-7 w-7 shrink-0 items-center justify-center self-center rounded-full bg-gray-25 text-gray-600", children: _jsx(Icon, { icon: "thumbtack-off-o", size: 16 }) }));
|
|
35
|
-
return (_jsxs("div", { "data-cp-name": "PinnedMessageItem", className: clsx("flex items-end gap-2 px-3 pb-4", isMine ? "justify-end" : "justify-start"), children: [isMine && unpinButton, _jsx(Dropdown, { menu: { items: contextMenuItems }, trigger: ["contextMenu"], open: contextMenuOpen, onOpenChange: onContextMenuOpenChange, overlayClassName: MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, children: _jsxs("div", { className: "relative min-w-0 cursor-pointer", onClick: () => onJump(message), children: [_jsx("div", { className: "pointer-events-none", children: bubbleNode }), pinnedBadgeNode] }) }), !isMine && unpinButton] }));
|
|
36
|
+
return (_jsxs("div", { "data-cp-name": "PinnedMessageItem", className: clsx("flex items-end gap-2 px-3 pb-4", isMine ? "justify-end" : "justify-start"), children: [isMine && canUnpin && unpinButton, _jsx(Dropdown, { menu: { items: contextMenuItems }, trigger: ["contextMenu"], open: contextMenuOpen, onOpenChange: onContextMenuOpenChange, overlayClassName: MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, children: _jsxs("div", { className: "relative min-w-0 cursor-pointer", onClick: () => onJump(message), children: [_jsx("div", { className: "pointer-events-none", children: bubbleNode }), pinnedBadgeNode] }) }), !isMine && canUnpin && unpinButton] }));
|
|
36
37
|
};
|
|
37
38
|
export default PinnedMessageItem;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
interface PinnedMessagesPanelProps {
|
|
2
2
|
open: boolean;
|
|
3
3
|
onClose: () => void;
|
|
4
|
+
canUnpin?: boolean;
|
|
4
5
|
}
|
|
5
|
-
declare const PinnedMessagesPanel: ({ open, onClose }: PinnedMessagesPanelProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
declare const PinnedMessagesPanel: ({ open, onClose, canUnpin, }: PinnedMessagesPanelProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
7
|
export default PinnedMessagesPanel;
|
|
7
8
|
//# sourceMappingURL=PinnedMessagesPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PinnedMessagesPanel.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/PinnedMessagesPanel.tsx"],"names":[],"mappings":"AAYA,UAAU,wBAAwB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"PinnedMessagesPanel.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/PinnedMessagesPanel.tsx"],"names":[],"mappings":"AAYA,UAAU,wBAAwB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,mBAAmB,GAAI,8BAI1B,wBAAwB,4CAqG1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -8,7 +8,7 @@ import useConversationStore from "../../store/conversation";
|
|
|
8
8
|
import { usePinMessage } from "../../hooks/message/usePinMessage";
|
|
9
9
|
import { emit } from "../../utils/events";
|
|
10
10
|
import PinnedMessageItem from "./PinnedMessageItem";
|
|
11
|
-
const PinnedMessagesPanel = ({ open, onClose }) => {
|
|
11
|
+
const PinnedMessagesPanel = ({ open, onClose, canUnpin = true, }) => {
|
|
12
12
|
const { t } = useTranslation();
|
|
13
13
|
const conversation = useConversationStore((state) => state.conversationData);
|
|
14
14
|
const selectedConversationId = useConversationStore((state) => state.selectedConversationId);
|
|
@@ -46,6 +46,6 @@ const PinnedMessagesPanel = ({ open, onClose }) => {
|
|
|
46
46
|
borderTopRightRadius: 16,
|
|
47
47
|
overflow: "hidden",
|
|
48
48
|
},
|
|
49
|
-
}, getContainer: false, forceRender: true, children: _jsxs("div", { className: "flex h-full flex-col bg-white", children: [_jsxs("div", { className: "flex items-center gap-4 border-b border-gray-25 px-3 py-4", children: [_jsx("span", { className: "flex-1 text-lg font-bold text-gray-900", children: t("pinned_panel_title") }), _jsx(Button, { type: "text", shape: "default", className: "h-6 w-6 p-0 text-gray-900", onClick: onClose, "aria-label": t("pinned_panel_title"), children: _jsx(Icon, { icon: "close-b", size: 24 }) })] }), _jsxs("div", { className: "flex flex-1 flex-col gap-3 overflow-y-auto py-3", children: [_jsx("p", { className: "px-3 text-sm leading-[160%] text-gray-600", children: t("pinned_panel_hint") }), pinnedMessageList.map((message) => (_jsx(PinnedMessageItem, { message: message, contextMenuOpen: openContextMenuId === message.clientMsgID, onContextMenuOpenChange: (isOpen) => setOpenContextMenuId(isOpen ? message.clientMsgID : null), onUnpin: handleUnpin, onJump: handleJump }, message.clientMsgID)))] })] }) }));
|
|
49
|
+
}, getContainer: false, forceRender: true, children: _jsxs("div", { className: "flex h-full flex-col bg-white", children: [_jsxs("div", { className: "flex items-center gap-4 border-b border-gray-25 px-3 py-4", children: [_jsx("span", { className: "flex-1 text-lg font-bold text-gray-900", children: t("pinned_panel_title") }), _jsx(Button, { type: "text", shape: "default", className: "h-6 w-6 p-0 text-gray-900", onClick: onClose, "aria-label": t("pinned_panel_title"), children: _jsx(Icon, { icon: "close-b", size: 24 }) })] }), _jsxs("div", { className: "flex flex-1 flex-col gap-3 overflow-y-auto py-3", children: [_jsx("p", { className: "px-3 text-sm leading-[160%] text-gray-600", children: t("pinned_panel_hint") }), pinnedMessageList.map((message) => (_jsx(PinnedMessageItem, { message: message, contextMenuOpen: openContextMenuId === message.clientMsgID, onContextMenuOpenChange: (isOpen) => setOpenContextMenuId(isOpen ? message.clientMsgID : null), onUnpin: handleUnpin, onJump: handleJump, canUnpin: canUnpin }, message.clientMsgID)))] })] }) }));
|
|
50
50
|
};
|
|
51
51
|
export default PinnedMessagesPanel;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreadProfilePanel.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ThreadProfilePanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"ThreadProfilePanel.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ThreadProfilePanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAU7E,UAAU,uBAAuB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,gBAAgB,CAAC;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;CACzD;AAED,QAAA,MAAM,kBAAkB,GAAI,oDAKzB,uBAAuB,4CA4GzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -6,22 +6,19 @@ import { useTranslation } from "react-i18next";
|
|
|
6
6
|
import { Icon } from "../../components/icon";
|
|
7
7
|
import MediaEntryCard from "../../components/media-resources/MediaEntryCard";
|
|
8
8
|
import { PeerType } from "../../types/conversation";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { resolvePeerBadgeColor } from "../../utils/conversation";
|
|
10
|
+
import { useConversationPeerIdentity } from "../../hooks/conversation/useConversationPeerIdentity";
|
|
11
11
|
import { useLeaveGroupAction } from "../../hooks/group/useLeaveGroupAction";
|
|
12
12
|
import LeaveGroupBlockedModal from "./LeaveGroupBlockedModal";
|
|
13
13
|
import LeaveGroupConfirmModal from "./LeaveGroupConfirmModal";
|
|
14
14
|
const PROFILE_AVATAR_SIZE = 96;
|
|
15
15
|
const ThreadProfilePanel = ({ open, conversation, onClose, onSelectResource, }) => {
|
|
16
16
|
const { t } = useTranslation("conversation-inbox");
|
|
17
|
-
const displayName =
|
|
18
|
-
const avatarUrl = useConversationAvatarUrl(conversation);
|
|
19
|
-
const peerType = conversation.peerType;
|
|
20
|
-
const badgeLabel = resolvePeerBadgeLabel(peerType, t);
|
|
17
|
+
const { displayName, avatarUrl, peerType, badgeLabel } = useConversationPeerIdentity(conversation);
|
|
21
18
|
const { canLeaveGroup, isPublicGroup, isLeaving, isConfirmOpen, isBlockedOpen, openLeaveGroup, confirmLeaveGroup, closeConfirm, closeBlocked, } = useLeaveGroupAction({
|
|
22
19
|
groupID: conversation.groupID,
|
|
23
20
|
conversationID: conversation.conversationID,
|
|
24
|
-
isGroupThread: peerType === PeerType.GROUP,
|
|
21
|
+
isGroupThread: conversation.peerType === PeerType.GROUP,
|
|
25
22
|
onLeft: onClose,
|
|
26
23
|
});
|
|
27
24
|
return (_jsxs(Drawer, { open: open, onClose: onClose, placement: "right", closeIcon: false, width: "100%", "data-cp-name": "ThreadProfilePanel", styles: {
|
|
@@ -8,6 +8,8 @@ interface MessageListProps {
|
|
|
8
8
|
onCopyMessageLink?: (conversationId: string, clientMsgID: string) => void;
|
|
9
9
|
/** Called instead of the SDK's default toast when a jumped-to message turns out to be revoked. */
|
|
10
10
|
onSearchMessageRevoked?: () => void;
|
|
11
|
+
/** Renders the pinned-message bar under the header (CRM desk only). */
|
|
12
|
+
showPinnedMessageBar?: boolean;
|
|
11
13
|
}
|
|
12
14
|
declare const MessageList: (props: MessageListProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
15
|
export default MessageList;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAkCA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IACpC,uEAAuE;IACvE,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAuX3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -26,12 +26,13 @@ import { isGroupConversation } from "../../utils/imCommon";
|
|
|
26
26
|
import { ConnectStatus, SessionStatus } from "../../types/chat";
|
|
27
27
|
import { PeerType } from "../../types/conversation";
|
|
28
28
|
import PinLimitModal from "../../components/conversation-detail/PinLimitModal";
|
|
29
|
+
import PinnedMessageBar from "../../components/conversation-detail/PinnedMessageBar";
|
|
29
30
|
import ConfirmModal from "../../components/common/ConfirmModal";
|
|
30
31
|
dayjs.extend(isToday);
|
|
31
32
|
const MessageList = (props) => {
|
|
32
33
|
const { t } = useTranslation();
|
|
33
34
|
const { user, connectStatus, allowPinMessageWithoutPermission } = useChatContext();
|
|
34
|
-
const { onClose, conversationId, searchClientMsgID, openCreateCannedModal, onOpenThreadInfo, onCopyMessageLink, onSearchMessageRevoked, } = props;
|
|
35
|
+
const { onClose, conversationId, searchClientMsgID, openCreateCannedModal, onOpenThreadInfo, onCopyMessageLink, onSearchMessageRevoked, showPinnedMessageBar = false, } = props;
|
|
35
36
|
const conversationData = useConversationStore((state) => state.conversationData);
|
|
36
37
|
const permissions = useGroupPermission(conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID);
|
|
37
38
|
const isGroupChat = isGroupConversation(conversationData !== null && conversationData !== void 0 ? conversationData : undefined);
|
|
@@ -192,7 +193,7 @@ const MessageList = (props) => {
|
|
|
192
193
|
if (!conversationData) {
|
|
193
194
|
return (_jsx("div", { className: "flex flex-1 items-center justify-center h-full", children: connectStatus !== ConnectStatus.Connected ? (_jsx(Spin, {})) : (_jsx(Empty, { description: t("no_conversation_data") })) }));
|
|
194
195
|
}
|
|
195
|
-
return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full min-w-0 overflow-hidden bg-white", "data-cp-name": "MessageList", children: [_jsx(MessageHeader, { onClose: onClose, currentSession: latestConversationSession, isJoined: isJoined, onOpenThreadInfo: onOpenThreadInfo }), _jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array, isGroupChat: isGroupChat, contextMenuOpen: openMenuId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenMenuId(open ? message.clientMsgID : null), onRevokeMessage: handleOpenRevoke, onQuoteMessage: setQuotedMessage, onPressQuoteMessage: onPressQuoteMessage, onPinMessage: canPinMessage ? handlePinMessage : undefined, onUnpinMessage: canPinMessage ? handleUnpinMessage : undefined, timeRevealed: revealedTimeMsgId === message.clientMsgID, onToggleTimeReveal: handleToggleTimeReveal, onCopyMessageLink: handleCopyMessageLink }, message.clientMsgID))) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), (Boolean(rawGroupId) && isCheckingMembership) || !isGroupStateFresh ? (_jsx("div", { className: "border-t bg-white py-4 flex items-center justify-center", children: _jsx(Spin, {}) })) : (latestConversationSession === null || latestConversationSession === void 0 ? void 0 : latestConversationSession.status) === SessionStatus.UNASSIGNED ? (_jsx(UnassignedSessionFooter, { sessionId: latestConversationSession.id, teamId: latestConversationSession.teamId })) : !isConfirmedGroup && shouldRestrictToLastSession ? (_jsxs("div", { className: "border-t bg-white py-4 flex flex-col items-center gap-2", "data-cp-name": "JoinGroupRequired", children: [_jsx("p", { className: "text-sm text-gray-500", children: t("join_group_required") }), _jsx(Button, { type: "primary", onClick: joinGroup, loading: isJoining, children: t("join_group") })] })) : isViewOnlyMember ? (
|
|
196
|
+
return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full min-w-0 overflow-hidden bg-white", "data-cp-name": "MessageList", children: [_jsx(MessageHeader, { onClose: onClose, currentSession: latestConversationSession, isJoined: isJoined, onOpenThreadInfo: onOpenThreadInfo }), showPinnedMessageBar && (_jsx(PinnedMessageBar, { genericSubtitle: true, canUnpin: canPinMessage })), _jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array, isGroupChat: isGroupChat, contextMenuOpen: openMenuId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenMenuId(open ? message.clientMsgID : null), onRevokeMessage: handleOpenRevoke, onQuoteMessage: setQuotedMessage, onPressQuoteMessage: onPressQuoteMessage, onPinMessage: canPinMessage ? handlePinMessage : undefined, onUnpinMessage: canPinMessage ? handleUnpinMessage : undefined, timeRevealed: revealedTimeMsgId === message.clientMsgID, onToggleTimeReveal: handleToggleTimeReveal, onCopyMessageLink: handleCopyMessageLink }, message.clientMsgID))) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), (Boolean(rawGroupId) && isCheckingMembership) || !isGroupStateFresh ? (_jsx("div", { className: "border-t bg-white py-4 flex items-center justify-center", children: _jsx(Spin, {}) })) : (latestConversationSession === null || latestConversationSession === void 0 ? void 0 : latestConversationSession.status) === SessionStatus.UNASSIGNED ? (_jsx(UnassignedSessionFooter, { sessionId: latestConversationSession.id, teamId: latestConversationSession.teamId })) : !isConfirmedGroup && shouldRestrictToLastSession ? (_jsxs("div", { className: "border-t bg-white py-4 flex flex-col items-center gap-2", "data-cp-name": "JoinGroupRequired", children: [_jsx("p", { className: "text-sm text-gray-500", children: t("join_group_required") }), _jsx(Button, { type: "primary", onClick: joinGroup, loading: isJoining, children: t("join_group") })] })) : isViewOnlyMember ? (
|
|
196
197
|
// Brief fallback while isJoined catches up after the kick event.
|
|
197
198
|
_jsx(MessageFooter, { currentSession: latestConversationSession, openCreateCannedModal: openCreateCannedModal })) : !canSendMessage ? (_jsx("div", { className: "border-t bg-[#f5f5f5] py-3 flex items-center justify-center", children: _jsx("p", { className: "text-sm text-gray-500", children: t(isRestrictedByGroupMute
|
|
198
199
|
? "send_message_disabled_group_mute"
|
|
@@ -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,8BAA8B,CAAC;
|
|
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,8BAA8B,CAAC;AA0CtC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,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;IACpD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAClD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,iBAAiB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACnD;AAkCD,QAAA,MAAM,WAAW,GAAI,0PAgBlB,gBAAgB,mDAoXlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -22,6 +22,7 @@ import SystemLogMessageItem from "./SystemLogMessage";
|
|
|
22
22
|
import GroupNotificationMessageItem from "./GroupNotificationMessage";
|
|
23
23
|
import SessionEventMessageItem from "./SessionEventMessage";
|
|
24
24
|
import { isGroupNotificationMessageType, isSessionEventMessage, isSystemLogMessageType, } from "../../../utils/messageLog";
|
|
25
|
+
import { isSupportSessionAgentView } from "../../../utils/conversation";
|
|
25
26
|
import { buildMessageToolboxMenuItems, getCopyableMessageText, isCopyableMessageType, isPinnableMessageType, MessageToolboxActionKey, MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, useMessageToolboxVisibility, } from "../../../components/message/toolbox";
|
|
26
27
|
const MESSAGE_AVATAR_SIZE = 24;
|
|
27
28
|
const DIVIDER_GAP_MINUTES = 30;
|
|
@@ -148,6 +149,7 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
|
|
|
148
149
|
const isSystemLogMessage = isSystemLogMessageType(message === null || message === void 0 ? void 0 : message.contentType);
|
|
149
150
|
const isGroupNotificationMessage = isGroupNotificationMessageType(message === null || message === void 0 ? void 0 : message.contentType);
|
|
150
151
|
const isSessionEvent = isSessionEventMessage(message);
|
|
152
|
+
const showsSessionEvents = isCrm || isSupportSessionAgentView(conversationData, userID);
|
|
151
153
|
const isStickerMessage = (message === null || message === void 0 ? void 0 : message.contentType) === MessageType.StickerMessage;
|
|
152
154
|
const hasContextMenu = contextMenuItems.length > 0;
|
|
153
155
|
const isLatestMine = ((_a = allMessages.find((m) => m.sendID === userID)) === null || _a === void 0 ? void 0 : _a.clientMsgID) ===
|
|
@@ -165,7 +167,7 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
|
|
|
165
167
|
// apps get an unexplained gap where the hidden session divider used to be.
|
|
166
168
|
const breaksGroup = (neighbour) => isSystemLogMessageType(neighbour.contentType) ||
|
|
167
169
|
isGroupNotificationMessageType(neighbour.contentType) ||
|
|
168
|
-
(isSessionEventMessage(neighbour) &&
|
|
170
|
+
(isSessionEventMessage(neighbour) && showsSessionEvents);
|
|
169
171
|
const prevBreaksGroup = immediatePrev ? breaksGroup(immediatePrev) : false;
|
|
170
172
|
const nextBreaksGroup = immediateNext ? breaksGroup(immediateNext) : false;
|
|
171
173
|
const prevSameUser = !isOrder &&
|
|
@@ -189,7 +191,7 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
|
|
|
189
191
|
const showAvatar = showPeerInfo && !isMine && !nextSameUser;
|
|
190
192
|
const showSenderName = showPeerInfo && !isMine && !prevSameUser;
|
|
191
193
|
const showTip = forceHideTip ? false : !nextSameUser;
|
|
192
|
-
if (isMessageHiddenForViewer(message, isCrm, conversationData !== null && conversationData !== void 0 ? conversationData : undefined)) {
|
|
194
|
+
if (isMessageHiddenForViewer(message, isCrm, conversationData !== null && conversationData !== void 0 ? conversationData : undefined, userID)) {
|
|
193
195
|
return null;
|
|
194
196
|
}
|
|
195
197
|
const messageContainerProps = {
|
|
@@ -208,8 +210,8 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
|
|
|
208
210
|
_jsx(GroupNotificationMessageItem, { message: message })));
|
|
209
211
|
}
|
|
210
212
|
if (isSessionEvent) {
|
|
211
|
-
//
|
|
212
|
-
if (!
|
|
213
|
+
// Owners in consumer apps don't see session dividers; CRM and agents do.
|
|
214
|
+
if (!showsSessionEvents)
|
|
213
215
|
return null;
|
|
214
216
|
return (_createElement("div", Object.assign({}, messageContainerProps, { key: message === null || message === void 0 ? void 0 : message.clientMsgID }),
|
|
215
217
|
timeBreakNode,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ConversationItem } from "@droppii-org/wasm-client-sdk";
|
|
2
|
+
import { PeerType } from "../../types/conversation";
|
|
3
|
+
export interface ConversationPeerIdentity {
|
|
4
|
+
displayName: string;
|
|
5
|
+
avatarUrl: string | null;
|
|
6
|
+
peerType: PeerType;
|
|
7
|
+
badgeLabel: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Who the thread header/profile should present. A support group's
|
|
11
|
+
* showName/faceURL is the bot's, so an agent viewing someone else's session
|
|
12
|
+
* sees the session owner instead.
|
|
13
|
+
*/
|
|
14
|
+
export declare const useConversationPeerIdentity: (conversation: ConversationItem) => ConversationPeerIdentity;
|
|
15
|
+
//# sourceMappingURL=useConversationPeerIdentity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useConversationPeerIdentity.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useConversationPeerIdentity.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAIrE,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAShD,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,GACtC,cAAc,gBAAgB,KAC7B,wBAsCF,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import { DChatSDK } from "../../constants/sdk";
|
|
5
|
+
import useAuthStore from "../../store/auth";
|
|
6
|
+
import useUsersInfoStore from "../../store/usersInfo";
|
|
7
|
+
import { PeerType } from "../../types/conversation";
|
|
8
|
+
import { isSupportSessionAgentView, resolveConversationDisplayName, resolvePeerBadgeLabel, resolveSupportSessionOwnerId, } from "../../utils/conversation";
|
|
9
|
+
import { useConversationAvatarUrl } from "./useConversationAvatarUrl";
|
|
10
|
+
/**
|
|
11
|
+
* Who the thread header/profile should present. A support group's
|
|
12
|
+
* showName/faceURL is the bot's, so an agent viewing someone else's session
|
|
13
|
+
* sees the session owner instead.
|
|
14
|
+
*/
|
|
15
|
+
export const useConversationPeerIdentity = (conversation) => {
|
|
16
|
+
var _a, _b;
|
|
17
|
+
const { t } = useTranslation("conversation-inbox");
|
|
18
|
+
const userID = useAuthStore((state) => state.userID);
|
|
19
|
+
const conversationAvatarUrl = useConversationAvatarUrl(conversation);
|
|
20
|
+
const ownerId = isSupportSessionAgentView(conversation, userID)
|
|
21
|
+
? resolveSupportSessionOwnerId(conversation)
|
|
22
|
+
: "";
|
|
23
|
+
const owner = useUsersInfoStore((state) => ownerId ? state.usersInfo[ownerId] : undefined);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (!ownerId || owner)
|
|
26
|
+
return;
|
|
27
|
+
DChatSDK.getUsersInfo([ownerId])
|
|
28
|
+
.then(({ data }) => useUsersInfoStore.getState().upsertUsers(data))
|
|
29
|
+
.catch((error) => {
|
|
30
|
+
console.error("Error fetching session owner info:", error);
|
|
31
|
+
});
|
|
32
|
+
}, [ownerId, owner]);
|
|
33
|
+
if (ownerId) {
|
|
34
|
+
return {
|
|
35
|
+
displayName: ((_a = owner === null || owner === void 0 ? void 0 : owner.nickname) === null || _a === void 0 ? void 0 : _a.trim()) || t("thread_card.fallback_name"),
|
|
36
|
+
avatarUrl: ((_b = owner === null || owner === void 0 ? void 0 : owner.faceURL) === null || _b === void 0 ? void 0 : _b.trim()) || null,
|
|
37
|
+
peerType: PeerType.USER,
|
|
38
|
+
badgeLabel: "",
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const peerType = conversation.peerType;
|
|
42
|
+
return {
|
|
43
|
+
displayName: resolveConversationDisplayName(conversation, t),
|
|
44
|
+
avatarUrl: conversationAvatarUrl,
|
|
45
|
+
peerType,
|
|
46
|
+
badgeLabel: resolvePeerBadgeLabel(peerType, t),
|
|
47
|
+
};
|
|
48
|
+
};
|
|
@@ -3,7 +3,8 @@ export declare const visibleTypeMessage: MessageType[];
|
|
|
3
3
|
export declare const isMessageHiddenForViewer: (message: MessageItem, isCrm: boolean, conversation?: {
|
|
4
4
|
peerType?: string;
|
|
5
5
|
conversationType?: number;
|
|
6
|
-
|
|
6
|
+
ex?: string;
|
|
7
|
+
}, viewerUserID?: string) => boolean;
|
|
7
8
|
export declare const useMessage: (conversationId?: string, searchClientMsgID?: string, enabled?: boolean, useAppHistory?: boolean, onSearchMessageRevoked?: () => void) => {
|
|
8
9
|
loadState: {
|
|
9
10
|
initLoading: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useMessage.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,WAAW,EACX,WAAW,EAEZ,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"useMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useMessage.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,WAAW,EACX,WAAW,EAEZ,MAAM,8BAA8B,CAAC;AAgBtC,eAAO,MAAM,kBAAkB,eAkB9B,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,SAAS,WAAW,EACpB,OAAO,OAAO,EACd,eAAe;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,EAC5E,eAAe,MAAM,KACpB,OA0BF,CAAC;AAEF,eAAO,MAAM,UAAU,GACrB,iBAAiB,MAAM,EACvB,oBAAoB,MAAM,EAC1B,iBAAc,EACd,uBAAqB,EAGrB,yBAAyB,MAAM,IAAI;;;;;qBAgBd,WAAW,EAAE;;;;;;qBAAb,WAAW,EAAE;;;;;;CAoVnC,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,SAAS,WAAW,SACpB,CAAC;AAChC,eAAO,MAAM,gBAAgB,GAAI,SAAS,WAAW,SACpB,CAAC;AAClC,eAAO,MAAM,gBAAgB,GAAI,aAAa,MAAM,SACf,CAAC;AAEtC,eAAO,MAAM,kBAAkB,GAC7B,aAAa,WAAW,EAAE,EAC1B,SAAS,WAAW,EACpB,WAAW,MAAM,GAAG,MAAM,KACzB,WAAW,GAAG,SAkBhB,CAAC;AAMF,eAAO,MAAM,oBAAoB,GAC/B,aAAa,WAAW,EAAE,EAC1B,SAAS,WAAW,EACpB,WAAW,MAAM,GAAG,MAAM,KACzB,WAAW,GAAG,SAQhB,CAAC"}
|
|
@@ -10,9 +10,10 @@ import isEmpty from "lodash/isEmpty";
|
|
|
10
10
|
import { useChatContext } from "../../context/ChatContext";
|
|
11
11
|
import useAuthStore from "../../store/auth";
|
|
12
12
|
import { ConnectStatus, SyncStatus } from "../../types/chat";
|
|
13
|
-
import { GROUP_NOTIFICATION_MESSAGE_TYPES, isGroupNotificationMessageType, isSystemLogMessageType } from "../../utils/messageLog";
|
|
13
|
+
import { GROUP_NOTIFICATION_MESSAGE_TYPES, isGroupNotificationMessageType, isSessionEventMessage, isSystemLogMessageType } from "../../utils/messageLog";
|
|
14
14
|
import { isRenderableCustomMessage } from "../../utils/customMessage";
|
|
15
15
|
import { isGroupConversation } from "../../utils/imCommon";
|
|
16
|
+
import { isSupportSessionAgentView } from "../../utils/conversation";
|
|
16
17
|
export const visibleTypeMessage = [
|
|
17
18
|
MessageType.TextMessage,
|
|
18
19
|
MessageType.PictureMessage,
|
|
@@ -32,7 +33,7 @@ export const visibleTypeMessage = [
|
|
|
32
33
|
MessageType.LogTextMessage,
|
|
33
34
|
...GROUP_NOTIFICATION_MESSAGE_TYPES,
|
|
34
35
|
];
|
|
35
|
-
export const isMessageHiddenForViewer = (message, isCrm, conversation) => {
|
|
36
|
+
export const isMessageHiddenForViewer = (message, isCrm, conversation, viewerUserID) => {
|
|
36
37
|
if (!visibleTypeMessage.includes(message === null || message === void 0 ? void 0 : message.contentType))
|
|
37
38
|
return true;
|
|
38
39
|
// Group notification messages stay hidden in a CX support session even
|
|
@@ -43,9 +44,14 @@ export const isMessageHiddenForViewer = (message, isCrm, conversation) => {
|
|
|
43
44
|
}
|
|
44
45
|
if (isCrm)
|
|
45
46
|
return false;
|
|
47
|
+
// An agent handling someone else's session (e.g. PDP CS) needs the
|
|
48
|
+
// assignment log and session dividers; the owner never sees them.
|
|
49
|
+
const isAgentView = isSupportSessionAgentView(conversation, viewerUserID);
|
|
50
|
+
if (isAgentView && isSessionEventMessage(message))
|
|
51
|
+
return false;
|
|
46
52
|
const isCustomMessage = MessageType.CustomMessage === (message === null || message === void 0 ? void 0 : message.contentType);
|
|
47
53
|
return (Boolean(message === null || message === void 0 ? void 0 : message.isInternal) ||
|
|
48
|
-
isSystemLogMessageType(message === null || message === void 0 ? void 0 : message.contentType) ||
|
|
54
|
+
(!isAgentView && isSystemLogMessageType(message === null || message === void 0 ? void 0 : message.contentType)) ||
|
|
49
55
|
(isCustomMessage && !isRenderableCustomMessage(message)));
|
|
50
56
|
};
|
|
51
57
|
export const useMessage = (conversationId, searchClientMsgID, enabled = true, useAppHistory = false,
|
|
@@ -69,6 +75,11 @@ onSearchMessageRevoked) => {
|
|
|
69
75
|
const latestLoadState = useLatest(loadState);
|
|
70
76
|
const canLoadRef = useLatest(canLoad);
|
|
71
77
|
const conversationIdRef = useLatest(conversationId);
|
|
78
|
+
const useAppHistoryRef = useLatest(useAppHistory);
|
|
79
|
+
// The load effect resets the list when the conversation or history mode
|
|
80
|
+
// changes; a response still in flight for the old one must not merge in.
|
|
81
|
+
const isStaleResponse = (reqConversationID, reqUseAppHistory) => conversationIdRef.current !== reqConversationID ||
|
|
82
|
+
useAppHistoryRef.current !== reqUseAppHistory;
|
|
72
83
|
// searchMessages can run more than once for a single user action — React
|
|
73
84
|
// StrictMode double-invokes the effect below in dev, and any change to its
|
|
74
85
|
// other deps (canLoad flipping as the SDK connects, userID arriving) re-runs
|
|
@@ -79,6 +90,7 @@ onSearchMessageRevoked) => {
|
|
|
79
90
|
const { loading: moreOldLoading, runAsync: getMoreOldMessages } = useRequest(async (loadMore = true) => {
|
|
80
91
|
var _a, _b, _c, _d, _e;
|
|
81
92
|
const reqConversationID = conversationId;
|
|
93
|
+
const reqUseAppHistory = useAppHistory;
|
|
82
94
|
const params = {
|
|
83
95
|
count: PAGE_SIZE.large,
|
|
84
96
|
startClientMsgID: loadMore
|
|
@@ -91,10 +103,10 @@ onSearchMessageRevoked) => {
|
|
|
91
103
|
const { data } = useAppHistory
|
|
92
104
|
? await DChatSDK.getAdvancedHistoryMessageListApp(params)
|
|
93
105
|
: await DChatSDK.getAdvancedHistoryMessageList(params);
|
|
94
|
-
if (
|
|
106
|
+
if (isStaleResponse(reqConversationID, reqUseAppHistory))
|
|
95
107
|
return;
|
|
96
108
|
setTimeout(() => {
|
|
97
|
-
if (
|
|
109
|
+
if (isStaleResponse(reqConversationID, reqUseAppHistory))
|
|
98
110
|
return;
|
|
99
111
|
setLoadState((preState) => {
|
|
100
112
|
// Always merge with preState (never discard it, even for the
|
|
@@ -109,7 +121,7 @@ onSearchMessageRevoked) => {
|
|
|
109
121
|
});
|
|
110
122
|
}
|
|
111
123
|
catch (_f) {
|
|
112
|
-
if (
|
|
124
|
+
if (isStaleResponse(reqConversationID, reqUseAppHistory))
|
|
113
125
|
return;
|
|
114
126
|
setLoadState((preState) => (Object.assign(Object.assign({}, preState), { initLoading: false })));
|
|
115
127
|
}
|
|
@@ -119,6 +131,7 @@ onSearchMessageRevoked) => {
|
|
|
119
131
|
const { loading: moreNewLoading, runAsync: getMoreNewMessages } = useRequest(async (loadMore = true) => {
|
|
120
132
|
var _a, _b;
|
|
121
133
|
const reqConversationID = conversationId;
|
|
134
|
+
const reqUseAppHistory = useAppHistory;
|
|
122
135
|
try {
|
|
123
136
|
const reverseParams = {
|
|
124
137
|
count: PAGE_SIZE.large,
|
|
@@ -131,10 +144,10 @@ onSearchMessageRevoked) => {
|
|
|
131
144
|
const { data } = useAppHistory
|
|
132
145
|
? await DChatSDK.getAdvancedHistoryMessageListReverseApp(reverseParams)
|
|
133
146
|
: await DChatSDK.getAdvancedHistoryMessageListReverse(reverseParams);
|
|
134
|
-
if (
|
|
147
|
+
if (isStaleResponse(reqConversationID, reqUseAppHistory))
|
|
135
148
|
return;
|
|
136
149
|
setTimeout(() => {
|
|
137
|
-
if (
|
|
150
|
+
if (isStaleResponse(reqConversationID, reqUseAppHistory))
|
|
138
151
|
return;
|
|
139
152
|
setLoadState((preState) => {
|
|
140
153
|
let messageList = [
|
|
@@ -147,7 +160,7 @@ onSearchMessageRevoked) => {
|
|
|
147
160
|
});
|
|
148
161
|
}
|
|
149
162
|
catch (_c) {
|
|
150
|
-
if (
|
|
163
|
+
if (isStaleResponse(reqConversationID, reqUseAppHistory))
|
|
151
164
|
return;
|
|
152
165
|
setLoadState((preState) => (Object.assign(Object.assign({}, preState), { initLoading: false })));
|
|
153
166
|
}
|
|
@@ -159,6 +172,7 @@ onSearchMessageRevoked) => {
|
|
|
159
172
|
if (!searchClientMsgID || !conversationId)
|
|
160
173
|
return;
|
|
161
174
|
const reqConversationID = conversationId;
|
|
175
|
+
const reqUseAppHistory = useAppHistory;
|
|
162
176
|
const searchPrevParams = {
|
|
163
177
|
count: PAGE_SIZE.small,
|
|
164
178
|
startClientMsgID: searchClientMsgID,
|
|
@@ -184,7 +198,7 @@ onSearchMessageRevoked) => {
|
|
|
184
198
|
},
|
|
185
199
|
]);
|
|
186
200
|
const currentMessages = ((_b = (_a = dataCurrent === null || dataCurrent === void 0 ? void 0 : dataCurrent.findResultItems) === null || _a === void 0 ? void 0 : _a.find((item) => item.conversationID === conversationId)) === null || _b === void 0 ? void 0 : _b.messageList) || [];
|
|
187
|
-
if (
|
|
201
|
+
if (isStaleResponse(reqConversationID, reqUseAppHistory))
|
|
188
202
|
return;
|
|
189
203
|
// Jumping to a message that has since been revoked: there is nothing to
|
|
190
204
|
// land on, so don't build the search window around it at all. Tell the
|
|
@@ -313,7 +327,7 @@ onSearchMessageRevoked) => {
|
|
|
313
327
|
messageList: [],
|
|
314
328
|
}));
|
|
315
329
|
};
|
|
316
|
-
}, [conversationId, searchClientMsgID, canLoad, userID]);
|
|
330
|
+
}, [conversationId, searchClientMsgID, canLoad, userID, useAppHistory]);
|
|
317
331
|
return {
|
|
318
332
|
loadState,
|
|
319
333
|
latestLoadState,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePinnedMessages.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/usePinnedMessages.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,GAAU,gBAAgB,MAAM,
|
|
1
|
+
{"version":3,"file":"usePinnedMessages.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/usePinnedMessages.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,GAAU,gBAAgB,MAAM,kBA2B/D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,gBAAgB,MAAM;;;;CAqBvD,CAAC"}
|
|
@@ -11,6 +11,12 @@ export const fetchPinnedMessages = async (conversationID) => {
|
|
|
11
11
|
offset: 0,
|
|
12
12
|
pageSize: PAGE_SIZE.small,
|
|
13
13
|
});
|
|
14
|
+
// The store holds one thread's pins; a reply that lands after the user
|
|
15
|
+
// switched threads would paint the old thread's pins into the new one.
|
|
16
|
+
const { selectedConversationId, conversationData } = useConversationStore.getState();
|
|
17
|
+
const activeConversationId = selectedConversationId || (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID);
|
|
18
|
+
if (activeConversationId !== conversationID)
|
|
19
|
+
return;
|
|
14
20
|
const sortedMessageList = [...(data.messageList || [])].sort((first, second) => (second.pinnedTime || 0) - (first.pinnedTime || 0));
|
|
15
21
|
setPinnedMessageData(sortedMessageList, data.totalCount || 0, (_a = data.remainingPinCount) !== null && _a !== void 0 ? _a : 0, (_b = data.isEnd) !== null && _b !== void 0 ? _b : true);
|
|
16
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/desk-message/index.tsx"],"names":[],"mappings":"AAWA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAE5E,UAAU,qBAAqB;IAC7B,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,gBAAgB,GAAI,8FAKvB,qBAAqB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/desk-message/index.tsx"],"names":[],"mappings":"AAWA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAE5E,UAAU,qBAAqB;IAC7B,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,gBAAgB,GAAI,8FAKvB,qBAAqB,4CA2CvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -14,6 +14,6 @@ const DChatDeskMessage = ({ openCreateCannedModal, groupThreadInfoConfig, onCopy
|
|
|
14
14
|
const searchClientMsgID = useConversationStore((state) => state.searchClientMsgID);
|
|
15
15
|
const [isThreadInfoOpen, { toggle: toggleThreadInfo, setFalse: closeThreadInfo },] = useBoolean(false);
|
|
16
16
|
const { connectStatus } = useChatContext();
|
|
17
|
-
return (_jsx(_Fragment, { children: connectStatus === ConnectStatus.Connected ? (_jsxs("div", { className: "flex flex-1 flex-row h-screen bg-[#f5f5f5]", children: [_jsx(DeskAssignedSession, {}), _jsx(DeskConversationList, {}), _jsx(MessageList, { conversationId: selectedConversationId, searchClientMsgID: searchClientMsgID, openCreateCannedModal: openCreateCannedModal, onOpenThreadInfo: toggleThreadInfo, onCopyMessageLink: onCopyMessageLink, onSearchMessageRevoked: onSearchMessageRevoked }), _jsx(ThreadInfo, { isOpen: isThreadInfoOpen, onClose: closeThreadInfo, groupConfig: groupThreadInfoConfig })] })) : (_jsx("div", { className: "flex flex-1 flex-row h-screen bg-[#f5f5f5]", children: connectStatus === ConnectStatus.Connecting && _jsx(Spin, { fullscreen: true }) })) }));
|
|
17
|
+
return (_jsx(_Fragment, { children: connectStatus === ConnectStatus.Connected ? (_jsxs("div", { className: "flex flex-1 flex-row h-screen bg-[#f5f5f5]", children: [_jsx(DeskAssignedSession, {}), _jsx(DeskConversationList, {}), _jsx(MessageList, { conversationId: selectedConversationId, searchClientMsgID: searchClientMsgID, openCreateCannedModal: openCreateCannedModal, onOpenThreadInfo: toggleThreadInfo, onCopyMessageLink: onCopyMessageLink, onSearchMessageRevoked: onSearchMessageRevoked, showPinnedMessageBar: true }), _jsx(ThreadInfo, { isOpen: isThreadInfoOpen, onClose: closeThreadInfo, groupConfig: groupThreadInfoConfig })] })) : (_jsx("div", { className: "flex flex-1 flex-row h-screen bg-[#f5f5f5]", children: connectStatus === ConnectStatus.Connecting && _jsx(Spin, { fullscreen: true }) })) }));
|
|
18
18
|
};
|
|
19
19
|
export default DChatDeskMessage;
|
|
@@ -3,6 +3,17 @@ import { ChatCategory, PeerType, type ConversationExtra } from "../types/convers
|
|
|
3
3
|
export declare const parseConversationExtra: (ex: string | undefined) => ConversationExtra;
|
|
4
4
|
export declare const resolveConversationChatCategory: (item: ConversationItem) => ChatCategory;
|
|
5
5
|
export declare const resolveConversationBotId: (item: ConversationItem) => string;
|
|
6
|
+
type SupportSessionSource = {
|
|
7
|
+
conversationID?: string;
|
|
8
|
+
conversationType?: number;
|
|
9
|
+
ex?: string;
|
|
10
|
+
} | null;
|
|
11
|
+
export declare const resolveSupportSessionOwnerId: (item?: SupportSessionSource) => string;
|
|
12
|
+
/**
|
|
13
|
+
* True when the viewer handles a support session someone else owns (e.g. a
|
|
14
|
+
* PDP CS agent). The owner — BIZ/Mall/Obefe customer — keeps the bot view.
|
|
15
|
+
*/
|
|
16
|
+
export declare const isSupportSessionAgentView: (item: SupportSessionSource | undefined, viewerUserID?: string) => boolean;
|
|
6
17
|
export declare const isBotPeer: (item: ConversationItem) => boolean;
|
|
7
18
|
export declare const isCustomerPeer: (item: ConversationItem) => boolean;
|
|
8
19
|
export declare const isGroupChat: (item: ConversationItem) => boolean;
|
|
@@ -32,4 +43,5 @@ export declare const getGroupIdFromConversationId: (conversationId?: string) =>
|
|
|
32
43
|
* matches selfUserId — guessing a peer there would open the wrong thread.
|
|
33
44
|
*/
|
|
34
45
|
export declare const getPeerUserIdFromConversationId: (conversationId?: string, selfUserId?: string) => string;
|
|
46
|
+
export {};
|
|
35
47
|
//# sourceMappingURL=conversation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/utils/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/utils/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAe,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EACL,YAAY,EACZ,QAAQ,EACR,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAC;AAW9B,eAAO,MAAM,sBAAsB,GACjC,IAAI,MAAM,GAAG,SAAS,KACrB,iBAcF,CAAC;AAEF,eAAO,MAAM,+BAA+B,GAC1C,MAAM,gBAAgB,KACrB,YAA4D,CAAC;AAEhE,eAAO,MAAM,wBAAwB,GAAI,MAAM,gBAAgB,KAAG,MAOjE,CAAC;AAEF,KAAK,oBAAoB,GAAG;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,GAAG,IAAI,CAAC;AAIT,eAAO,MAAM,4BAA4B,GACvC,OAAO,oBAAoB,KAC1B,MAiBF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,GACpC,MAAM,oBAAoB,GAAG,SAAS,EACtC,eAAe,MAAM,KACpB,OAGF,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,MAAM,gBAAgB,YAChB,CAAC;AAEjC,eAAO,MAAM,cAAc,GAAI,MAAM,gBAAgB,YAChB,CAAC;AAEtC,eAAO,MAAM,WAAW,GAAI,MAAM,gBAAgB,YAChB,CAAC;AAEnC,eAAO,MAAM,8BAA8B,GACzC,MAAM,gBAAgB,EACtB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,KACzB,MAKF,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,MAAM,gBAAgB,KACrB,MAAM,GAAG,IAGX,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,UAAU,QAAQ,EAClB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,KACzB,MAIF,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,UAAU,QAAQ,8EAIvD,CAAC;AAKF;;;;;;;;;GASG;AACH,eAAO,MAAM,4BAA4B,GAAI,iBAAiB,MAAM,WAG5D,CAAC;AAET;;;;;;;;;GASG;AACH,eAAO,MAAM,+BAA+B,GAC1C,iBAAiB,MAAM,EACvB,aAAa,MAAM,KAClB,MAYF,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SessionType } from "@droppii-org/wasm-client-sdk";
|
|
1
2
|
import { ChatCategory, PeerType, } from "../types/conversation";
|
|
2
3
|
import { DChatApplicationType, } from "../types/chat";
|
|
3
4
|
const DEFAULT_CONVERSATION_EXTRA = {
|
|
@@ -30,6 +31,37 @@ export const resolveConversationBotId = (item) => {
|
|
|
30
31
|
return "";
|
|
31
32
|
}
|
|
32
33
|
};
|
|
34
|
+
const BOT_SESSION_CONVERSATION_PREFIX = "sg_bot_";
|
|
35
|
+
export const resolveSupportSessionOwnerId = (item) => {
|
|
36
|
+
var _a, _b, _c, _d;
|
|
37
|
+
if (!item)
|
|
38
|
+
return "";
|
|
39
|
+
if (item.conversationType === SessionType.Group) {
|
|
40
|
+
try {
|
|
41
|
+
const parsed = JSON.parse(item.ex || "{}");
|
|
42
|
+
const ownerId = (_c = (_b = (_a = parsed.sessionInfo) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.ownerId) === null || _c === void 0 ? void 0 : _c.trim();
|
|
43
|
+
if (ownerId)
|
|
44
|
+
return ownerId;
|
|
45
|
+
}
|
|
46
|
+
catch (_e) {
|
|
47
|
+
// fall through to the id
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Core leaves ex empty on some rows; "sg_bot_<botId>_<ownerId>" always
|
|
51
|
+
// carries the owner, so the verdict can't flip between sources.
|
|
52
|
+
const conversationID = (_d = item.conversationID) !== null && _d !== void 0 ? _d : "";
|
|
53
|
+
return conversationID.startsWith(BOT_SESSION_CONVERSATION_PREFIX)
|
|
54
|
+
? conversationID.slice(conversationID.lastIndexOf("_") + 1)
|
|
55
|
+
: "";
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* True when the viewer handles a support session someone else owns (e.g. a
|
|
59
|
+
* PDP CS agent). The owner — BIZ/Mall/Obefe customer — keeps the bot view.
|
|
60
|
+
*/
|
|
61
|
+
export const isSupportSessionAgentView = (item, viewerUserID) => {
|
|
62
|
+
const ownerId = resolveSupportSessionOwnerId(item);
|
|
63
|
+
return !!ownerId && !!viewerUserID && ownerId !== viewerUserID;
|
|
64
|
+
};
|
|
33
65
|
export const isBotPeer = (item) => item.peerType === PeerType.BOT;
|
|
34
66
|
export const isCustomerPeer = (item) => item.peerType === PeerType.CUSTOMER;
|
|
35
67
|
export const isGroupChat = (item) => item.peerType === PeerType.GROUP;
|