@droppii-org/chat-sdk 0.7.3 → 0.7.4
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/boot/BootProgressBar.d.ts +13 -0
- package/dist/components/boot/BootProgressBar.d.ts.map +1 -0
- package/dist/components/boot/BootProgressBar.js +18 -0
- package/dist/components/canned-response/CannedResponsePanel.d.ts.map +1 -1
- package/dist/components/canned-response/CannedResponsePanel.js +2 -2
- package/dist/components/common/BottomSheet.d.ts +18 -0
- package/dist/components/common/BottomSheet.d.ts.map +1 -0
- package/dist/components/common/BottomSheet.js +49 -0
- package/dist/components/common/DeskPanelDrawer.d.ts.map +1 -1
- package/dist/components/common/DeskPanelDrawer.js +29 -15
- package/dist/components/common/DeskSidePanel.d.ts.map +1 -1
- package/dist/components/common/DeskSidePanel.js +1 -1
- package/dist/components/compose/ComposeNewMessageModal.d.ts.map +1 -1
- package/dist/components/compose/ComposeNewMessageModal.js +3 -3
- package/dist/components/conversation/ConversationByGroupItem.d.ts.map +1 -1
- package/dist/components/conversation/ConversationByGroupItem.js +3 -8
- package/dist/components/conversation/ConversationBySessionItem.d.ts.map +1 -1
- package/dist/components/conversation/ConversationBySessionItem.js +3 -8
- package/dist/components/conversation/DeskConversationList.d.ts +4 -1
- package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
- package/dist/components/conversation/DeskConversationList.js +2 -2
- package/dist/components/conversation/DeskListHeader.d.ts +2 -0
- package/dist/components/conversation/DeskListHeader.d.ts.map +1 -1
- package/dist/components/conversation/DeskListHeader.js +3 -3
- package/dist/components/conversation-detail/ConversationMessageList.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationMessageList.js +1 -1
- package/dist/components/conversation-inbox/ConversationInboxList.d.ts.map +1 -1
- package/dist/components/conversation-inbox/ConversationInboxList.js +12 -3
- package/dist/components/conversation-inbox/InboxBootStatus.d.ts +10 -0
- package/dist/components/conversation-inbox/InboxBootStatus.d.ts.map +1 -0
- package/dist/components/conversation-inbox/InboxBootStatus.js +34 -0
- package/dist/components/conversation-inbox/InboxListSkeleton.d.ts +6 -0
- package/dist/components/conversation-inbox/InboxListSkeleton.d.ts.map +1 -0
- package/dist/components/conversation-inbox/InboxListSkeleton.js +8 -0
- package/dist/components/group/GroupPanelHeader.js +1 -1
- package/dist/components/icon/strokeIconNodes.d.ts +6 -0
- package/dist/components/icon/strokeIconNodes.d.ts.map +1 -1
- package/dist/components/icon/strokeIconNodes.js +5 -0
- package/dist/components/message/MessageHeader.d.ts +3 -1
- package/dist/components/message/MessageHeader.d.ts.map +1 -1
- package/dist/components/message/MessageHeader.js +10 -6
- 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 +15 -4
- package/dist/components/message/SelectSession.js +1 -1
- package/dist/components/message/footer/ActionBar.d.ts.map +1 -1
- package/dist/components/message/footer/ActionBar.js +2 -2
- package/dist/components/message/footer/ComposerTabs.js +1 -1
- package/dist/components/message/footer/CrmComposerCard.js +1 -1
- package/dist/components/message/footer/EmojiPicker.d.ts +3 -1
- package/dist/components/message/footer/EmojiPicker.d.ts.map +1 -1
- package/dist/components/message/footer/EmojiPicker.js +3 -2
- package/dist/components/message/footer/EnterHandler.d.ts.map +1 -1
- package/dist/components/message/footer/EnterHandler.js +16 -2
- package/dist/components/message/footer/MediaActions.d.ts +2 -1
- package/dist/components/message/footer/MediaActions.d.ts.map +1 -1
- package/dist/components/message/footer/MediaActions.js +4 -4
- package/dist/components/message/footer/ToolbarPlugin.js +1 -1
- package/dist/components/message/footer/mention/MentionMenu.js +1 -1
- package/dist/components/message/headerIconButton.js +1 -1
- package/dist/components/message/item/MessageMoreButton.d.ts.map +1 -1
- package/dist/components/message/item/MessageMoreButton.js +18 -5
- package/dist/components/message/item/QuoteMessage.d.ts.map +1 -1
- package/dist/components/message/item/QuoteMessage.js +3 -50
- package/dist/components/message/reply/ReplyPreviewBar.d.ts.map +1 -1
- package/dist/components/message/reply/ReplyPreviewBar.js +4 -13
- package/dist/components/rich-text-editor/RichTextEditor.d.ts +3 -1
- package/dist/components/rich-text-editor/RichTextEditor.d.ts.map +1 -1
- package/dist/components/rich-text-editor/RichTextEditor.js +4 -2
- package/dist/components/search-conversation/item/SearchItemAsGroup.d.ts.map +1 -1
- package/dist/components/search-conversation/item/SearchItemAsGroup.js +3 -3
- package/dist/components/search-conversation/item/SearchItemAsMessage.d.ts.map +1 -1
- package/dist/components/search-conversation/item/SearchItemAsMessage.js +10 -0
- package/dist/components/search-conversation/item/SearchItemAsUser.d.ts.map +1 -1
- package/dist/components/search-conversation/item/SearchItemAsUser.js +6 -0
- package/dist/components/session/DeskAssignedSession.js +2 -2
- package/dist/components/session/FolderRow.js +1 -1
- package/dist/components/thread/ManualAssignPopover.d.ts.map +1 -1
- package/dist/components/thread/ManualAssignPopover.js +13 -6
- package/dist/components/thread/SessionDetailCard.js +1 -1
- package/dist/components/thread/SessionTagPicker.js +1 -1
- package/dist/components/thread/SupportSessionPanel.d.ts +1 -1
- package/dist/components/thread/SupportSessionPanel.d.ts.map +1 -1
- package/dist/components/thread/SupportSessionPanel.js +1 -1
- package/dist/components/thread/ThreadInfo.d.ts.map +1 -1
- package/dist/components/thread/ThreadInfo.js +3 -1
- package/dist/components/thread/ThreadInfoHeader.d.ts +1 -1
- package/dist/components/thread/ThreadInfoHeader.d.ts.map +1 -1
- package/dist/components/thread/ThreadInfoHeader.js +1 -1
- package/dist/components/thread/UserSection.js +2 -2
- package/dist/constants/layout.d.ts +10 -1
- package/dist/constants/layout.d.ts.map +1 -1
- package/dist/constants/layout.js +10 -1
- package/dist/hooks/common/useDeskShortcuts.d.ts.map +1 -1
- package/dist/hooks/common/useDeskShortcuts.js +3 -1
- package/dist/hooks/common/useIsDeskWorkspaceMounted.d.ts +3 -0
- package/dist/hooks/common/useIsDeskWorkspaceMounted.d.ts.map +1 -0
- package/dist/hooks/common/useIsDeskWorkspaceMounted.js +4 -0
- package/dist/hooks/common/useViewportTier.d.ts +4 -0
- package/dist/hooks/common/useViewportTier.d.ts.map +1 -0
- package/dist/hooks/common/useViewportTier.js +9 -0
- package/dist/hooks/common/useVisualViewportHeight.d.ts +10 -0
- package/dist/hooks/common/useVisualViewportHeight.d.ts.map +1 -0
- package/dist/hooks/common/useVisualViewportHeight.js +30 -0
- package/dist/hooks/conversation/useConversationList.d.ts.map +1 -1
- package/dist/hooks/conversation/useConversationList.js +31 -0
- package/dist/hooks/conversation/useDeskOfflineLock.d.ts +9 -0
- package/dist/hooks/conversation/useDeskOfflineLock.d.ts.map +1 -0
- package/dist/hooks/conversation/useDeskOfflineLock.js +46 -0
- package/dist/hooks/conversation/useDeskThreadNavigation.d.ts +19 -0
- package/dist/hooks/conversation/useDeskThreadNavigation.d.ts.map +1 -0
- package/dist/hooks/conversation/useDeskThreadNavigation.js +68 -0
- package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
- package/dist/hooks/global/useGlobalEvent.js +22 -2
- package/dist/hooks/group/useCreateGroup.d.ts.map +1 -1
- package/dist/hooks/group/useCreateGroup.js +4 -4
- package/dist/hooks/init/useChatBootPhase.d.ts +30 -0
- package/dist/hooks/init/useChatBootPhase.d.ts.map +1 -0
- package/dist/hooks/init/useChatBootPhase.js +72 -0
- package/dist/hooks/message/usePinMessage.d.ts +0 -2
- package/dist/hooks/message/usePinMessage.d.ts.map +1 -1
- package/dist/hooks/message/usePinMessage.js +7 -11
- package/dist/hooks/message/useQuotedSenderName.d.ts +14 -0
- package/dist/hooks/message/useQuotedSenderName.d.ts.map +1 -0
- package/dist/hooks/message/useQuotedSenderName.js +41 -0
- package/dist/hooks/user/useAuth.d.ts.map +1 -1
- package/dist/hooks/user/useAuth.js +2 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/locales/i18n.d.ts.map +1 -1
- package/dist/locales/i18n.js +3 -2
- package/dist/locales/i18n.ts +3 -2
- package/dist/locales/vi/boot.json +28 -0
- package/dist/locales/vi/common.json +1 -1
- package/dist/screens/conversation-detail/index.d.ts.map +1 -1
- package/dist/screens/conversation-detail/index.js +8 -3
- package/dist/screens/desk-message/DeskBootCard.d.ts +7 -0
- package/dist/screens/desk-message/DeskBootCard.d.ts.map +1 -0
- package/dist/screens/desk-message/DeskBootCard.js +69 -0
- package/dist/screens/desk-message/DeskOfflineOverlay.d.ts +10 -0
- package/dist/screens/desk-message/DeskOfflineOverlay.d.ts.map +1 -0
- package/dist/screens/desk-message/DeskOfflineOverlay.js +11 -0
- package/dist/screens/desk-message/DeskWorkspace.d.ts +7 -1
- package/dist/screens/desk-message/DeskWorkspace.d.ts.map +1 -1
- package/dist/screens/desk-message/DeskWorkspace.js +82 -13
- package/dist/screens/desk-message/DeskWorkspaceSkeleton.d.ts +10 -0
- package/dist/screens/desk-message/DeskWorkspaceSkeleton.d.ts.map +1 -0
- package/dist/screens/desk-message/DeskWorkspaceSkeleton.js +18 -0
- package/dist/screens/desk-message/PhoneThreadFallbackHeader.d.ts +8 -0
- package/dist/screens/desk-message/PhoneThreadFallbackHeader.d.ts.map +1 -0
- package/dist/screens/desk-message/PhoneThreadFallbackHeader.js +11 -0
- package/dist/screens/desk-message/index.d.ts +2 -0
- package/dist/screens/desk-message/index.d.ts.map +1 -1
- package/dist/screens/desk-message/index.js +47 -3
- package/dist/store/boot.d.ts +29 -0
- package/dist/store/boot.d.ts.map +1 -0
- package/dist/store/boot.js +21 -0
- package/dist/store/conversation.d.ts +2 -0
- package/dist/store/conversation.d.ts.map +1 -1
- package/dist/store/conversation.js +13 -12
- package/dist/store/deskPanelHost.d.ts +2 -0
- package/dist/store/deskPanelHost.d.ts.map +1 -1
- package/dist/store/deskPanelHost.js +1 -0
- package/dist/store/type.d.ts +4 -1
- package/dist/store/type.d.ts.map +1 -1
- package/dist/store/workspaceLayout.d.ts +3 -0
- package/dist/store/workspaceLayout.d.ts.map +1 -1
- package/dist/store/workspaceLayout.js +2 -0
- package/dist/styles/global.css +1 -1
- package/dist/utils/conversation.d.ts +1 -0
- package/dist/utils/conversation.d.ts.map +1 -1
- package/dist/utils/conversation.js +1 -1
- package/package.json +1 -1
- package/dist/screens/desk-message/ViewportNotice.d.ts +0 -4
- package/dist/screens/desk-message/ViewportNotice.d.ts.map +0 -1
- package/dist/screens/desk-message/ViewportNotice.js +0 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strokeIconNodes.d.ts","sourceRoot":"","sources":["../../../src/components/icon/strokeIconNodes.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE1E,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"strokeIconNodes.d.ts","sourceRoot":"","sources":["../../../src/components/icon/strokeIconNodes.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAE1E,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiRc,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,iBAAiB,CAAC"}
|
|
@@ -135,6 +135,11 @@ export const STROKE_ICON_NODES = {
|
|
|
135
135
|
["polyline", { points: "16 17 21 12 16 7" }],
|
|
136
136
|
["line", { x1: "21", y1: "12", x2: "9", y2: "12" }],
|
|
137
137
|
],
|
|
138
|
+
"menu": [
|
|
139
|
+
["line", { x1: "3", y1: "12", x2: "21", y2: "12" }],
|
|
140
|
+
["line", { x1: "3", y1: "6", x2: "21", y2: "6" }],
|
|
141
|
+
["line", { x1: "3", y1: "18", x2: "21", y2: "18" }],
|
|
142
|
+
],
|
|
138
143
|
"message-circle": [
|
|
139
144
|
["path", { d: "M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" }],
|
|
140
145
|
],
|
|
@@ -5,6 +5,8 @@ interface MessageHeaderProps {
|
|
|
5
5
|
currentSession?: ISessionResponse;
|
|
6
6
|
isJoined?: boolean | null;
|
|
7
7
|
onOpenThreadInfo?: () => void;
|
|
8
|
+
/** Phone desk: back button before the avatar. */
|
|
9
|
+
onBack?: () => void;
|
|
8
10
|
}
|
|
9
11
|
type SelectSessionValueType = SessionStatus | SessionTag;
|
|
10
12
|
export interface SelectSessionOption {
|
|
@@ -14,6 +16,6 @@ export interface SelectSessionOption {
|
|
|
14
16
|
tintColorClassnameBg: string;
|
|
15
17
|
bgTintColorClassname: string;
|
|
16
18
|
}
|
|
17
|
-
declare const MessageHeader: ({ onClose, currentSession, isJoined, onOpenThreadInfo, }: MessageHeaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
declare const MessageHeader: ({ onClose, currentSession, isJoined, onOpenThreadInfo, onBack, }: MessageHeaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
18
20
|
export default MessageHeader;
|
|
19
21
|
//# sourceMappingURL=MessageHeader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageHeader.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MessageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageHeader.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AASzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAgB/C,UAAU,kBAAkB;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,KAAK,sBAAsB,GAAG,aAAa,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,sBAAsB,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,QAAA,MAAM,aAAa,GAAI,kEAMpB,kBAAkB,4CAmbpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Avatar, Button, message } from "antd";
|
|
4
4
|
import { Icon } from "../../components/icon";
|
|
5
|
+
import { StrokeIcon } from "../../components/icon/StrokeIcon";
|
|
5
6
|
import { useConversationDisplayData } from "../../hooks/conversation/useConversation";
|
|
6
7
|
import useConversationStore from "../../store/conversation";
|
|
7
8
|
import MediaCollection from "../../components/media-collection";
|
|
@@ -27,7 +28,7 @@ import { PeerType } from "../../types/conversation";
|
|
|
27
28
|
import { shouldShowHeaderMemberCount } from "../../utils/headerMemberCount";
|
|
28
29
|
import TintedAvatar from "../../components/common/TintedAvatar";
|
|
29
30
|
import { splitDisplayName } from "../../components/conversation/rowDisplayName";
|
|
30
|
-
const MessageHeader = ({ onClose, currentSession, isJoined, onOpenThreadInfo, }) => {
|
|
31
|
+
const MessageHeader = ({ onClose, currentSession, isJoined, onOpenThreadInfo, onBack, }) => {
|
|
31
32
|
var _a, _b, _c, _d;
|
|
32
33
|
const { t } = useTranslation();
|
|
33
34
|
const isCx = useAuthStore((state) => state.isCx);
|
|
@@ -202,11 +203,14 @@ const MessageHeader = ({ onClose, currentSession, isJoined, onOpenThreadInfo, })
|
|
|
202
203
|
setCurrentSessionStatus(currentSession.status);
|
|
203
204
|
}
|
|
204
205
|
}, [currentSession]);
|
|
206
|
+
const avatarNode = (_jsx(_Fragment, { children: showOwnerPlaceholder ? (_jsx("span", { "aria-hidden": true, className: "h-10 w-10 shrink-0 animate-pulse rounded-full bg-gray-25" })) : ownerIdentity ? (isCrm ? (_jsx(TintedAvatar, { name: headerShortName, src: ownerIdentity.avatarUrl, size: 40 })) : (_jsx(Avatar, { src: ownerIdentity.avatarUrl, size: "large", alt: "", className: "min-w-10 min-h-10", children: ((_c = headerName === null || headerName === void 0 ? void 0 : headerName.charAt) === null || _c === void 0 ? void 0 : _c.call(headerName, 0)) || "A" }))) : shouldShowMemberCount ? (_jsx(GroupCompositeAvatar, { groupID: conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID, faceURL: avatar, ownerUserID: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.ownerUserID, groupName: displayName, size: 40, className: "min-w-10 min-h-10" })) : isCrm ? (_jsx(TintedAvatar, { name: headerShortName, src: avatar, size: 40 })) : (_jsx(Avatar, { src: avatar, size: "large", alt: "", className: "min-w-10 min-h-10", children: ((_d = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _d === void 0 ? void 0 : _d.call(displayName, 0)) || "A" })) }));
|
|
205
207
|
return (_jsxs("div", { className: `px-4 py-3 flex items-center border-b gap-3 bg-white ${isCrm
|
|
206
|
-
? "flex-nowrap border-gray-25 [container-type:inline-size]"
|
|
207
|
-
: "flex-wrap"}`, "data-cp-name": "MessageHeader", children: [
|
|
208
|
-
? "shrink-0 gap-3 [@container(max-width:699px)]:gap-2"
|
|
209
|
-
: "gap-2 overflow-hidden"}`, children: [_jsxs("div", { className: isCrm
|
|
208
|
+
? "flex-nowrap border-gray-25 [container-type:inline-size] max-lg:flex-wrap phone:gap-2 phone:px-3"
|
|
209
|
+
: "flex-wrap"}`, "data-cp-name": "MessageHeader", children: [onBack && (_jsx(Button, { type: "text", shape: "default", "data-desk-back": true, className: "h-10 w-10 shrink-0 p-0 text-gray-900", onClick: onBack, "aria-label": t("back"), children: _jsx(StrokeIcon, { name: "chevron-left", size: 20 }) })), isCrm ? (_jsx("span", { className: "contents phone:hidden", children: avatarNode })) : (avatarNode), _jsxs("div", { className: `flex flex-col overflow-hidden flex-1 ${isCrm ? "min-w-[96px] max-[359px]:min-w-[72px]" : ""}`, children: [showOwnerPlaceholder ? (_jsxs("span", { "aria-hidden": true, className: "flex flex-col gap-1.5 py-0.5", children: [_jsx("span", { className: "h-4 w-36 animate-pulse rounded bg-gray-25" }), _jsx("span", { className: "h-3 w-24 animate-pulse rounded bg-gray-25" })] })) : (_jsx("p", { className: `text-base truncate ${isCrm ? "m-0 font-semibold leading-[normal] text-gray-900" : ""}`, title: headerName || undefined, children: (isCrm ? headerShortName : headerName) || "" })), showMemberCountLine && (_jsx("p", { className: "text-xs text-gray-500 truncate", children: t("member_count", { count: memberCount }) })), isCrm && !showOwnerPlaceholder && metaParts.length > 0 && (_jsx("p", { className: "m-0 flex min-w-0 items-center gap-1 overflow-hidden whitespace-nowrap text-xs text-gray-600 [container-type:inline-size]", "data-testid": "header-meta-line", children: metaParts.map((part, index) => (_jsxs(Fragment, { children: [index > 0 && (_jsx("span", { "aria-hidden": true, className: "h-[3px] w-[3px] shrink-0 rounded-full bg-gray-200" })), part] }, index))) }))] }), _jsxs("div", { className: `flex items-center justify-end ${isCrm
|
|
210
|
+
? "shrink-0 gap-3 [@container(max-width:699px)]:gap-2 max-lg:contents"
|
|
211
|
+
: "gap-2 overflow-hidden"}`, children: [_jsxs("div", { className: isCrm
|
|
212
|
+
? "flex items-center gap-2 max-lg:order-last max-lg:w-full max-lg:empty:hidden"
|
|
213
|
+
: "contents", children: [isCx && !isRealGroup && (_jsx(SelectSession, { placeholder: t(isCrm ? "reply_status_placeholder" : "select_tag"), options: tagOptions, value: currentSessionTag, onChange: (value) => handleUpdateSession(value, "tag", value === currentSessionTag), excludeOptions: [SessionTag.SLOW_PROCESSING, SessionTag.NONE] })), isCx && !isRealGroup && (_jsx(SelectSession, { placeholder: t("select_status"), options: statusOptions, value: isEnding ? SessionStatus.COMPLETED : currentSessionStatus, disabled: isEnding, onChange: (value) => handleUpdateSession(value, "status", value === currentSessionStatus) }))] }), _jsxs("div", { className: isCrm
|
|
210
214
|
? "flex items-center gap-1 [@container(max-width:699px)]:gap-0.5"
|
|
211
215
|
: "contents", children: [_jsx(SearchDrawer, {}), canViewMemberList && (_jsx(GroupMembersDrawer, { groupID: conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID, conversationId: conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID, currentSession: currentSession })), _jsx(MediaCollection, {}), _jsx(Button, { type: "text", shape: "default", className: headerIconButtonClass(isCrm, isInfoPanelOpen), onClick: handleInfoToggle, "aria-label": t("thread_info_open"), title: t("thread_info_open"), children: _jsx(HeaderIcon, { isCrm: isCrm, stroke: "panel-right", font: "align-justify-o" }) }), !!onClose && (_jsx(Button, { type: "text", shape: "default", className: "text-[var(--dc-color-header-icon)] w-8 h-8 p-0", onClick: onClose, "aria-label": t("close"), children: _jsx(Icon, { icon: "close-b", size: 22 }) }))] })] }), isCrm && currentSession && (_jsx(EndSessionConfirm, { open: isEndConfirmOpen, session: currentSession, customerName: headerName || "", onConfirm: () => {
|
|
212
216
|
setIsEndConfirmOpen(false);
|
|
@@ -11,6 +11,8 @@ interface MessageListProps {
|
|
|
11
11
|
onSearchMessageRevoked?: () => void;
|
|
12
12
|
/** Renders the pinned-message bar under the header (CRM desk only). */
|
|
13
13
|
showPinnedMessageBar?: boolean;
|
|
14
|
+
/** Phone desk: shows a back button in the header. */
|
|
15
|
+
onBack?: () => void;
|
|
14
16
|
}
|
|
15
17
|
declare const MessageList: (props: MessageListProps) => import("react/jsx-runtime").JSX.Element;
|
|
16
18
|
export default MessageList;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAIxD,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,CAAC,OAAO,CAAC,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAChE,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;
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAIxD,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,CAAC,OAAO,CAAC,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAChE,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;IAC/B,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAub3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useMessage } from "../../hooks/message/useMessage";
|
|
4
4
|
import { Button, Empty, Spin, message as toastMessage } from "antd";
|
|
5
|
+
import clsx from "clsx";
|
|
5
6
|
import { useCallback, useEffect, useState } from "react";
|
|
6
7
|
import dayjs from "dayjs";
|
|
7
8
|
import isToday from "dayjs/plugin/isToday";
|
|
@@ -37,7 +38,7 @@ dayjs.extend(isToday);
|
|
|
37
38
|
const MessageList = (props) => {
|
|
38
39
|
const { t } = useTranslation();
|
|
39
40
|
const { user, connectStatus, allowPinMessageWithoutPermission } = useChatContext();
|
|
40
|
-
const { onClose, conversationId, searchClientMsgID, openCreateCannedModal, onOpenThreadInfo, onCopyMessageLink, onSearchMessageRevoked, showPinnedMessageBar = false, } = props;
|
|
41
|
+
const { onClose, conversationId, searchClientMsgID, openCreateCannedModal, onOpenThreadInfo, onCopyMessageLink, onSearchMessageRevoked, showPinnedMessageBar = false, onBack, } = props;
|
|
41
42
|
const isCrm = useAuthStore((state) => state.isCrm);
|
|
42
43
|
const conversationData = useConversationStore((state) => state.conversationData);
|
|
43
44
|
const permissions = useGroupPermission(conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID);
|
|
@@ -202,6 +203,16 @@ const MessageList = (props) => {
|
|
|
202
203
|
emitter.off("UPDATE_SESSION", handler);
|
|
203
204
|
};
|
|
204
205
|
}, [conversationId, refetchConversationSessions]);
|
|
206
|
+
// Phone desk: a deep-linked thread shows loading, then the empty state if it never arrives.
|
|
207
|
+
const [loadTimedOut, setLoadTimedOut] = useState(false);
|
|
208
|
+
const isLoadingThread = Boolean(onBack && conversationId && !loadTimedOut);
|
|
209
|
+
useEffect(() => {
|
|
210
|
+
setLoadTimedOut(false);
|
|
211
|
+
if (!onBack || !conversationId || conversationData)
|
|
212
|
+
return;
|
|
213
|
+
const timer = setTimeout(() => setLoadTimedOut(true), 8000);
|
|
214
|
+
return () => clearTimeout(timer);
|
|
215
|
+
}, [onBack, conversationId, conversationData]);
|
|
205
216
|
useEffect(() => {
|
|
206
217
|
if (!openMenuId)
|
|
207
218
|
return;
|
|
@@ -213,9 +224,9 @@ const MessageList = (props) => {
|
|
|
213
224
|
return () => scrollContainer.removeEventListener("scroll", close);
|
|
214
225
|
}, [openMenuId]);
|
|
215
226
|
if (!conversationData) {
|
|
216
|
-
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") })) }));
|
|
227
|
+
return (_jsx("div", { className: clsx("flex flex-1 items-center justify-center h-full", onBack && "min-h-0"), children: connectStatus !== ConnectStatus.Connected || isLoadingThread ? (_jsx(Spin, {})) : (_jsx(Empty, { description: t("no_conversation_data") })) }));
|
|
217
228
|
}
|
|
218
|
-
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 })), _jsxs("div", { className: "relative flex min-h-0 flex-1 flex-col", children: [!loadState.initLoading && showJumpButton && (_jsx(UnreadMessageJumpButton, { className: "absolute right-0 top-4 z-10", onClick: handleJumpToFirstUnread })), _jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, containerProps: isCrm
|
|
229
|
+
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, onBack: onBack }), showPinnedMessageBar && (_jsx(PinnedMessageBar, { genericSubtitle: true, canUnpin: canPinMessage })), _jsxs("div", { className: "relative flex min-h-0 flex-1 flex-col", children: [!loadState.initLoading && showJumpButton && (_jsx(UnreadMessageJumpButton, { className: "absolute right-0 top-4 z-10", onClick: handleJumpToFirstUnread })), _jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, containerProps: isCrm
|
|
219
230
|
? {
|
|
220
231
|
role: "log",
|
|
221
232
|
"aria-live": "off",
|
|
@@ -223,7 +234,7 @@ const MessageList = (props) => {
|
|
|
223
234
|
tabIndex: 0,
|
|
224
235
|
onKeyDown: handleMessageLogKeyDown,
|
|
225
236
|
}
|
|
226
|
-
: undefined, 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, showUnreadDivider: !!unreadDividerMessageId &&
|
|
237
|
+
: undefined, 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: onCopyMessageLink ? handleCopyMessageLink : undefined, showUnreadDivider: !!unreadDividerMessageId &&
|
|
227
238
|
message.clientMsgID === unreadDividerMessageId, onUnreadDividerSeen: markDividerSeen }, 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 ? (
|
|
228
239
|
// Brief fallback while isJoined catches up after the kick event.
|
|
229
240
|
_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
|
|
@@ -18,7 +18,7 @@ const SelectSession = ({ options, value, onChange, excludeOptions, placeholder,
|
|
|
18
18
|
onChange(val);
|
|
19
19
|
};
|
|
20
20
|
return (_jsx("div", { className: "relative shrink-0", "data-cp-name": "SelectSession", children: _jsx(Select, { className: isCrm
|
|
21
|
-
? `!h-8 ${crmClassName !== null && crmClassName !== void 0 ? crmClassName : ""} [&_.ant-select-selection-item]:!pe-0 [&_.ant-select-selector]:!h-8 [&_.ant-select-selector]:!pl-[10px] [&_.ant-select-selector]:!pr-[26px] [&_.ant-select-selection-item]:!text-[13px] [&_.ant-select-selection-item]:!font-medium [&_.ant-select-selection-placeholder]:!text-[13px] [&_.ant-select-arrow]:!end-[6px]`
|
|
21
|
+
? `!h-8 touch:!h-10 touch:[&_.ant-select-selector]:!h-10 touch:[&_.ant-select-selection-item]:!leading-[38px] touch:[&_.ant-select-selection-placeholder]:!leading-[38px] ${crmClassName !== null && crmClassName !== void 0 ? crmClassName : ""} [&_.ant-select-selection-item]:!pe-0 [&_.ant-select-selector]:!h-8 [&_.ant-select-selector]:!pl-[10px] [&_.ant-select-selector]:!pr-[26px] [&_.ant-select-selection-item]:!text-[13px] [&_.ant-select-selection-item]:!font-medium [&_.ant-select-selection-placeholder]:!text-[13px] [&_.ant-select-arrow]:!end-[6px]`
|
|
22
22
|
: `${selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.bgTintColorClassname} custom-select min-w-[100px]`, popupClassName: isCrm
|
|
23
23
|
? "[&_.ant-select-item-option-selected]:!bg-primary-25 [&_.ant-select-item-option-selected]:!font-normal"
|
|
24
24
|
: undefined, placement: "bottomLeft", placeholder: placeholder, "aria-label": placeholder, options: selectOptions, value: selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value, onSelect: handleSelect, disabled: disabled, popupMatchSelectWidth: false, suffixIcon: isCrm ? (_jsx(StrokeIcon, { name: "chevron-down", size: 16, className: "text-gray-600" })) : (_jsx(Icon, { icon: "angle-down-o", className: `${isCrm ? "text-gray-600" : selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.tintColorClassname} mt-[2px]`, size: 14 })), menuItemSelectedIcon: null, labelRender: () => ["NONE", ""].includes(selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionBar.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/ActionBar.tsx"],"names":[],"mappings":"AA4BA,UAAU,cAAc;IAEtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,QAAA,MAAM,SAAS,GAAI,gCAAwC,cAAc,
|
|
1
|
+
{"version":3,"file":"ActionBar.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/ActionBar.tsx"],"names":[],"mappings":"AA4BA,UAAU,cAAc;IAEtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,QAAA,MAAM,SAAS,GAAI,gCAAwC,cAAc,4CAmKxE,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -97,9 +97,9 @@ const ActionBar = ({ formatOpen = false, onToggleFormat }) => {
|
|
|
97
97
|
});
|
|
98
98
|
}, [editor]);
|
|
99
99
|
if (isCrm) {
|
|
100
|
-
return (_jsxs("div", { "data-cp-name": "ActionBar", className: "flex items-center gap-0.5", children: [_jsx(Button, { type: "text", shape: "default", "aria-label": t("composer_format"), title: t("composer_format"), "aria-pressed": formatOpen, onClick: onToggleFormat, className: clsx("!flex !h-8 !w-8 items-center justify-center rounded-lg p-0 hover:!bg-gray-5 hover:!text-gray-900", formatOpen ? "!bg-primary-25 !text-primary-500" : "text-gray-600"), children: _jsx(StrokeIcon, { name: "type", size: 18 }) }), _jsx(MediaActions, { crmComposer: true, listUploadFiles: listUploadFiles, onFilesChange: setListUploadFiles }), _jsx("span", { className: "flex-1" }), _jsxs("button", { type: "button", onClick: handleSend, disabled: !canSend, className: clsx("flex h-8 items-center gap-1.5 whitespace-nowrap rounded-lg border px-3.5 text-sm font-medium text-white focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-400", isInternal
|
|
100
|
+
return (_jsxs("div", { "data-cp-name": "ActionBar", className: "flex items-center gap-0.5", children: [_jsx(Button, { type: "text", shape: "default", "aria-label": t("composer_format"), title: t("composer_format"), "aria-pressed": formatOpen, onClick: onToggleFormat, className: clsx("!flex !h-8 !w-8 items-center justify-center rounded-lg p-0 hover:!bg-gray-5 hover:!text-gray-900 touch:min-h-10 touch:min-w-10", formatOpen ? "!bg-primary-25 !text-primary-500" : "text-gray-600"), children: _jsx(StrokeIcon, { name: "type", size: 18 }) }), _jsx(MediaActions, { crmComposer: true, hideEmojiOnPhone: true, listUploadFiles: listUploadFiles, onFilesChange: setListUploadFiles }), _jsx("span", { className: "flex-1" }), _jsxs("button", { type: "button", onClick: handleSend, disabled: !canSend, "aria-label": isInternal ? t("composer_send_note") : t("composer_send"), className: clsx("flex h-8 items-center gap-1.5 whitespace-nowrap rounded-lg border px-3.5 text-sm font-medium text-white touch:min-h-10 max-[359px]:w-10 max-[359px]:justify-center max-[359px]:px-0 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-400", isInternal
|
|
101
101
|
? "border-warning-800 bg-warning-800 hover:bg-warning-900"
|
|
102
|
-
: "border-primary-400 bg-primary-400 hover:bg-primary-500", !canSend && "cursor-not-allowed opacity-40"), children: [_jsx(StrokeIcon, { name: "send", size: 18 }), isInternal ? t("composer_send_note") : t("composer_send")] })] }));
|
|
102
|
+
: "border-primary-400 bg-primary-400 hover:bg-primary-500", !canSend && "cursor-not-allowed opacity-40"), children: [_jsx(StrokeIcon, { name: "send", size: 18 }), _jsx("span", { className: "max-[359px]:sr-only", children: isInternal ? t("composer_send_note") : t("composer_send") })] })] }));
|
|
103
103
|
}
|
|
104
104
|
return (_jsxs("div", { "data-cp-name": "ActionBar", className: "flex items-center justify-between px-4", children: [_jsx(MediaActions, { listUploadFiles: listUploadFiles, onFilesChange: setListUploadFiles, buttonClassName: "text-gray-500 w-8 h-8 p-0" }), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: handleSend, disabled: !canSend, children: _jsx(Icon, { icon: "send-b", size: 28, className: `${canSend ? "text-[var(--dc-color-primary)]" : "text-gray-400"}` }) })] }));
|
|
105
105
|
};
|
|
@@ -16,7 +16,7 @@ const ComposerTabs = ({ canUseInternal, isInternal, lockToInternal, setIsInterna
|
|
|
16
16
|
return (_jsx("div", { role: "group", "aria-label": t("composer_mode_label"), "data-cp-name": "ComposerTabs", className: "flex shrink-0 gap-0.5 rounded-lg bg-[var(--dc-color-neutral-surface)] p-1", children: MODES.map(({ isInternal: modeIsInternal, labelKey, icon }) => {
|
|
17
17
|
const selected = isInternal === modeIsInternal;
|
|
18
18
|
const disabled = lockToInternal && !modeIsInternal;
|
|
19
|
-
return (_jsxs("button", { type: "button", "aria-pressed": selected, disabled: disabled, onClick: () => setIsInternal(modeIsInternal), className: clsx("flex h-7 items-center gap-1.5 whitespace-nowrap rounded px-2.5 text-[13px] focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-400", selected
|
|
19
|
+
return (_jsxs("button", { type: "button", "aria-pressed": selected, disabled: disabled, onClick: () => setIsInternal(modeIsInternal), className: clsx("flex h-7 touch:min-h-10 items-center gap-1.5 whitespace-nowrap rounded px-2.5 text-[13px] focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-400", selected
|
|
20
20
|
? clsx("bg-white font-semibold shadow-[0_1px_2px_rgba(57,62,64,0.12)]", modeIsInternal ? "text-warning-800" : "text-gray-900")
|
|
21
21
|
: "font-medium text-gray-600 hover:text-gray-900", disabled && "cursor-not-allowed opacity-50"), children: [_jsx(StrokeIcon, { name: icon, size: 16 }), t(labelKey)] }, labelKey));
|
|
22
22
|
}) }));
|
|
@@ -21,7 +21,7 @@ const CrmComposerCard = ({ canUseInternal, isInternal, lockToInternal, setIsInte
|
|
|
21
21
|
}, [replyLocked]);
|
|
22
22
|
return (_jsxs("div", { "data-cp-name": "CrmComposerCard", "data-internal": isInternal, className: clsx("flex flex-col gap-1.5 rounded-xl border p-2", isInternal
|
|
23
23
|
? "border-warning-400/60 bg-warning-25"
|
|
24
|
-
: "border-[color:var(--dc-composer-border)] bg-[var(--dc-composer-bg)] focus-within:border-[color:var(--dc-composer-border-focus)] focus-within:shadow-[0_0_0_3px_var(--dc-color-primary-light)]", replyLocked && "opacity-50"), children: [_jsxs("div", { className: "flex items-center justify-between gap-2 [container-type:inline-size]", children: [_jsx(ComposerTabs, { canUseInternal: canUseInternal, isInternal: isInternal, lockToInternal: lockToInternal, setIsInternal: setIsInternal }), isInternal ? (_jsxs("span", { role: "note", title: t("composer_internal_notice"), className: "flex min-w-0 items-center gap-1 whitespace-nowrap text-xs font-medium text-warning-800", children: [_jsx(StrokeIcon, { name: "lock", size: 14 }), _jsx("span", { className: "truncate [@container(max-width:419px)]:sr-only", children: t("composer_internal_notice") })] })) : (_jsxs("span", { className: "ml-auto flex min-w-0 items-center gap-1 overflow-hidden whitespace-nowrap text-xs text-gray-600 [@container(max-width:309px)]:!hidden", children: [_jsx(Kbd, { children: "Enter" }), " ", t("composer_hint_enter"), _jsxs("span", { className: "flex items-center gap-1 [@container(max-width:499px)]:!hidden", children: ["\u00B7 ", _jsx(Kbd, { children: "Shift" }), " + ", _jsx(Kbd, { children: "Enter" }), " ", t("composer_hint_newline")] })] }))] }), _jsxs("div", { ref: fieldRef, className: "contents", children: [_jsx(ComposerEditor, { isInternal: isInternal, placeholderText: isInternal
|
|
24
|
+
: "border-[color:var(--dc-composer-border)] bg-[var(--dc-composer-bg)] focus-within:border-[color:var(--dc-composer-border-focus)] focus-within:shadow-[0_0_0_3px_var(--dc-color-primary-light)]", replyLocked && "opacity-50"), children: [_jsxs("div", { className: "flex items-center justify-between gap-2 [container-type:inline-size]", children: [_jsx(ComposerTabs, { canUseInternal: canUseInternal, isInternal: isInternal, lockToInternal: lockToInternal, setIsInternal: setIsInternal }), isInternal ? (_jsxs("span", { role: "note", title: t("composer_internal_notice"), className: "flex min-w-0 items-center gap-1 whitespace-nowrap text-xs font-medium text-warning-800", children: [_jsx(StrokeIcon, { name: "lock", size: 14 }), _jsx("span", { className: "truncate [@container(max-width:419px)]:sr-only", children: t("composer_internal_notice") })] })) : (_jsxs("span", { className: "ml-auto flex min-w-0 items-center gap-1 overflow-hidden whitespace-nowrap text-xs text-gray-600 [@container(max-width:309px)]:!hidden touch:!hidden", children: [_jsx(Kbd, { children: "Enter" }), " ", t("composer_hint_enter"), _jsxs("span", { className: "flex items-center gap-1 [@container(max-width:499px)]:!hidden", children: ["\u00B7 ", _jsx(Kbd, { children: "Shift" }), " + ", _jsx(Kbd, { children: "Enter" }), " ", t("composer_hint_newline")] })] }))] }), _jsxs("div", { ref: fieldRef, className: "contents", children: [_jsx(ComposerEditor, { isInternal: isInternal, placeholderText: isInternal
|
|
25
25
|
? t("composer_internal_placeholder")
|
|
26
26
|
: replyLocked
|
|
27
27
|
? t("composer_closed_placeholder")
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
interface EmojiPickerProps {
|
|
2
2
|
onEmojiSelect: (emoji: string) => void;
|
|
3
3
|
onClose: () => void;
|
|
4
|
+
/** Extra classes for the root (CRM clamps the width on tablets). */
|
|
5
|
+
className?: string;
|
|
4
6
|
}
|
|
5
|
-
declare const EmojiPicker: ({ onEmojiSelect, onClose }: EmojiPickerProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
declare const EmojiPicker: ({ onEmojiSelect, onClose, className }: EmojiPickerProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
8
|
export default EmojiPicker;
|
|
7
9
|
//# sourceMappingURL=EmojiPicker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmojiPicker.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/EmojiPicker.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EmojiPicker.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/EmojiPicker.tsx"],"names":[],"mappings":"AAMA,UAAU,gBAAgB;IACxB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,WAAW,GAAI,uCAAuC,gBAAgB,4CAiM3E,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState } from "react";
|
|
4
|
+
import clsx from "clsx";
|
|
4
5
|
import { useTranslation } from "react-i18next";
|
|
5
|
-
const EmojiPicker = ({ onEmojiSelect, onClose }) => {
|
|
6
|
+
const EmojiPicker = ({ onEmojiSelect, onClose, className }) => {
|
|
6
7
|
const { t } = useTranslation("common");
|
|
7
8
|
const [activeCategory, setActiveCategory] = useState("smileys");
|
|
8
9
|
const emojiCategories = {
|
|
@@ -148,7 +149,7 @@ const EmojiPicker = ({ onEmojiSelect, onClose }) => {
|
|
|
148
149
|
],
|
|
149
150
|
},
|
|
150
151
|
};
|
|
151
|
-
return (_jsx("div", { "data-cp-name": "EmojiPicker", className: "absolute bottom-full left-0 mb-2 bg-white border border-gray-200 rounded-xl shadow-lg w-96 z-50", children: _jsxs("div", { className: "p-3", children: [_jsxs("div", { className: "flex items-center justify-between mb-3", children: [_jsx("h3", { className: "font-medium text-gray-900", children: t("choose_emoji") }), _jsx("button", { onClick: onClose, className: "text-gray-400 hover:text-gray-600 text-xl", children: "\u00D7" })] }), _jsx("div", { className: "flex gap-1 mb-3", children: Object.entries(emojiCategories).map(([key, category]) => (_jsx("button", { onClick: () => setActiveCategory(key), className: `px-3 py-1 text-xs rounded-full transition-colors ${activeCategory === key
|
|
152
|
+
return (_jsx("div", { "data-cp-name": "EmojiPicker", className: clsx("absolute bottom-full left-0 mb-2 bg-white border border-gray-200 rounded-xl shadow-lg w-96 z-50", className), children: _jsxs("div", { className: "p-3", children: [_jsxs("div", { className: "flex items-center justify-between mb-3", children: [_jsx("h3", { className: "font-medium text-gray-900", children: t("choose_emoji") }), _jsx("button", { onClick: onClose, className: "text-gray-400 hover:text-gray-600 text-xl", children: "\u00D7" })] }), _jsx("div", { className: "flex gap-1 mb-3", children: Object.entries(emojiCategories).map(([key, category]) => (_jsx("button", { onClick: () => setActiveCategory(key), className: `px-3 py-1 text-xs rounded-full transition-colors ${activeCategory === key
|
|
152
153
|
? "bg-blue-100 text-blue-600"
|
|
153
154
|
: "text-gray-500 hover:text-gray-700"}`, children: category.name }, key))) }), _jsx("div", { className: "grid grid-cols-8 gap-1 max-h-48 overflow-y-auto", children: emojiCategories[activeCategory].emojis.map((emoji, index) => (_jsx("button", { onClick: () => onEmojiSelect(emoji), className: "p-2 text-xl hover:bg-gray-100 rounded-lg transition-colors", children: emoji }, index))) })] }) }));
|
|
154
155
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnterHandler.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/EnterHandler.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EnterHandler.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/EnterHandler.tsx"],"names":[],"mappings":"AA2BA,MAAM,CAAC,OAAO,UAAU,YAAY,SA+JnC"}
|
|
@@ -10,10 +10,13 @@ import { useMessageFooterContext } from ".";
|
|
|
10
10
|
import useConversationStore from "../../../store/conversation";
|
|
11
11
|
import emitter, { emit } from "../../../utils/events";
|
|
12
12
|
import { extractMentions } from "./mention/extractMentions";
|
|
13
|
+
import useAuthStore from "../../../store/auth";
|
|
14
|
+
import { LAYOUT_MEDIA } from "../../../constants/layout";
|
|
13
15
|
export default function EnterHandler() {
|
|
14
16
|
const [editor] = useLexicalComposerContext();
|
|
15
17
|
const { onSendMessage, isInternal, listUploadFiles, isOpenCanned, activeCannedIndex, isMentionMenuOpen, } = useMessageFooterContext();
|
|
16
18
|
const shiftEnterCount = useRef(0);
|
|
19
|
+
const isCrm = useAuthStore((state) => state.isCrm);
|
|
17
20
|
const quotedMessage = useConversationStore((state) => state.quotedMessage);
|
|
18
21
|
useEffect(() => {
|
|
19
22
|
return editor.registerCommand(KEY_ENTER_COMMAND, (event) => {
|
|
@@ -23,9 +26,19 @@ export default function EnterHandler() {
|
|
|
23
26
|
return false;
|
|
24
27
|
}
|
|
25
28
|
// Case 1: Enter (submit, chặn xuống dòng)
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
// Only CRM tolerates a null event; other hosts keep the original strict path.
|
|
30
|
+
const shift = isCrm ? event === null || event === void 0 ? void 0 : event.shiftKey : event.shiftKey;
|
|
31
|
+
if (!shift) {
|
|
28
32
|
shiftEnterCount.current = 0;
|
|
33
|
+
// CRM touch < 1024: leave the keydown untouched so Lexical (or iOS's native
|
|
34
|
+
// beforeinput) inserts the paragraph; the Send button sends.
|
|
35
|
+
if (isCrm && !isOpenCanned && window.matchMedia(LAYOUT_MEDIA.touch).matches) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
// A null event (IME composition end) has nothing to send or cancel on desktop.
|
|
39
|
+
if (isCrm && !event)
|
|
40
|
+
return true;
|
|
41
|
+
event.preventDefault();
|
|
29
42
|
if (isOpenCanned) {
|
|
30
43
|
emit("CANNED_RESPONSE_SELECT", activeCannedIndex);
|
|
31
44
|
return true;
|
|
@@ -108,6 +121,7 @@ export default function EnterHandler() {
|
|
|
108
121
|
isOpenCanned,
|
|
109
122
|
activeCannedIndex,
|
|
110
123
|
isMentionMenuOpen,
|
|
124
|
+
isCrm,
|
|
111
125
|
]);
|
|
112
126
|
useEffect(() => {
|
|
113
127
|
const clearEditor = () => {
|
|
@@ -5,7 +5,8 @@ interface MediaActionsProps {
|
|
|
5
5
|
buttonClassName?: string;
|
|
6
6
|
showMediaUpload?: boolean;
|
|
7
7
|
crmComposer?: boolean;
|
|
8
|
+
hideEmojiOnPhone?: boolean;
|
|
8
9
|
}
|
|
9
|
-
export default function MediaActions({ listUploadFiles, onFilesChange, buttonClassName, showMediaUpload, crmComposer, }: MediaActionsProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export default function MediaActions({ listUploadFiles, onFilesChange, buttonClassName, showMediaUpload, crmComposer, hideEmojiOnPhone, }: MediaActionsProps): import("react/jsx-runtime").JSX.Element;
|
|
10
11
|
export {};
|
|
11
12
|
//# sourceMappingURL=MediaActions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MediaActions.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/MediaActions.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAkB,UAAU,EAA0B,MAAM,MAAM,CAAC;AAuD1E,UAAU,iBAAiB;IACzB,eAAe,EAAE,UAAU,EAAE,CAAC;IAC9B,aAAa,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,WAAW,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"MediaActions.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/MediaActions.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAkB,UAAU,EAA0B,MAAM,MAAM,CAAC;AAuD1E,UAAU,iBAAiB;IACzB,eAAe,EAAE,UAAU,EAAE,CAAC;IAC9B,aAAa,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;IAC7C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,eAAe,EACf,aAAa,EACb,eAAe,EACf,eAAsB,EACtB,WAAmB,EACnB,gBAAwB,GACzB,EAAE,iBAAiB,2CA+LnB"}
|
|
@@ -18,7 +18,7 @@ import useAuthStore from "../../../store/auth";
|
|
|
18
18
|
import { StrokeIcon } from "../../../components/icon/StrokeIcon";
|
|
19
19
|
const EmojiIcon = (_jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M7.59997 12.4C7.59997 12.4 8.49997 13.2 9.99997 13.2C11.5 13.2 12.4 12.4 12.4 12.4M14 8.39997C14 8.8418 13.6418 9.19997 13.2 9.19997C12.7581 9.19997 12.4 8.8418 12.4 8.39997C12.4 7.95814 12.7581 7.59997 13.2 7.59997C13.6418 7.59997 14 7.95814 14 8.39997ZM18 9.99997C18 14.4182 14.4182 18 9.99997 18C5.58169 18 1.99997 14.4182 1.99997 9.99997C1.99997 5.58169 5.58169 1.99997 9.99997 1.99997C14.4182 1.99997 18 5.58169 18 9.99997ZM7.59997 8.39997C7.59997 8.8418 7.2418 9.19997 6.79997 9.19997C6.35814 9.19997 5.99997 8.8418 5.99997 8.39997C5.99997 7.95814 6.35814 7.59997 6.79997 7.59997C7.2418 7.59997 7.59997 7.95814 7.59997 8.39997Z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
20
20
|
const AttachIcon = (_jsx("svg", { width: "22", height: "22", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M15.6 10.0001V11.2001C15.6 14.5137 12.9137 17.2001 9.59998 17.2001C6.28626 17.2001 3.59998 14.5137 3.59998 11.2001V6.79999C3.59998 4.59085 5.39084 2.79999 7.59998 2.79999C9.8091 2.79999 11.6 4.59085 11.6 6.79999V11.2C11.6 12.3045 10.7045 13.2 9.59998 13.2C8.49542 13.2 7.59998 12.3045 7.59998 11.2V7.99999", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
|
|
21
|
-
export default function MediaActions({ listUploadFiles, onFilesChange, buttonClassName, showMediaUpload = true, crmComposer = false, }) {
|
|
21
|
+
export default function MediaActions({ listUploadFiles, onFilesChange, buttonClassName, showMediaUpload = true, crmComposer = false, hideEmojiOnPhone = false, }) {
|
|
22
22
|
const [editor] = useLexicalComposerContext();
|
|
23
23
|
const { t } = useTranslation();
|
|
24
24
|
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
|
|
@@ -96,14 +96,14 @@ export default function MediaActions({ listUploadFiles, onFilesChange, buttonCla
|
|
|
96
96
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
97
97
|
}, []);
|
|
98
98
|
const btnClass = crmComposer
|
|
99
|
-
? "!flex !h-8 !w-8 items-center justify-center rounded-lg p-0 text-gray-600 hover:!bg-gray-5 hover:!text-gray-900"
|
|
99
|
+
? "!flex !h-8 !w-8 items-center justify-center rounded-lg p-0 text-gray-600 hover:!bg-gray-5 hover:!text-gray-900 touch:min-h-10 touch:min-w-10"
|
|
100
100
|
: buttonClassName !== null && buttonClassName !== void 0 ? buttonClassName : "w-8 h-8 p-0 text-gray-500 hover:text-gray-700 hover:bg-gray-100";
|
|
101
101
|
const activeCls = crmComposer
|
|
102
102
|
? "!bg-primary-25 !text-primary-500"
|
|
103
103
|
: "bg-blue-100 text-blue-600";
|
|
104
104
|
const crmLabel = (key) => crmComposer ? { "aria-label": t(key), title: t(key) } : {};
|
|
105
|
-
return (_jsxs("div", { "data-cp-name": "MediaActions", className: clsx("flex items-center relative", crmComposer ? "gap-0.5" : "gap-1"), ref: containerRef, children: [isCrm && (_jsx(Button, Object.assign({ type: "text", shape: "default", className: clsx(btnClass, isOpenCanned && activeCls), onClick: onPressCanned }, crmLabel("composer_quick_reply"), { children: crmComposer ? (_jsx(StrokeIcon, { name: "hash", size: 18 })) : (_jsx(CannedResponseIcon, { className: clsx("hover:text-gray-700", isOpenCanned && "text-blue-600") })) }))), _jsx(Button, Object.assign({ type: "text", shape: "default", className: clsx(btnClass, showEmojiPicker &&
|
|
105
|
+
return (_jsxs("div", { "data-cp-name": "MediaActions", className: clsx("flex items-center relative", crmComposer ? "gap-0.5" : "gap-1"), ref: containerRef, children: [isCrm && (_jsx(Button, Object.assign({ type: "text", shape: "default", className: clsx(btnClass, isOpenCanned && activeCls), onClick: onPressCanned }, crmLabel("composer_quick_reply"), { children: crmComposer ? (_jsx(StrokeIcon, { name: "hash", size: 18 })) : (_jsx(CannedResponseIcon, { className: clsx("hover:text-gray-700", isOpenCanned && "text-blue-600") })) }))), _jsx(Button, Object.assign({ type: "text", shape: "default", className: clsx(btnClass, hideEmojiOnPhone && "phone:!hidden", showEmojiPicker &&
|
|
106
106
|
(crmComposer
|
|
107
107
|
? activeCls
|
|
108
|
-
: "bg-[var(--dc-color-primary-light)] text-[var(--dc-color-primary)]")), onClick: () => setShowEmojiPicker(!showEmojiPicker) }, crmLabel("composer_emoji"), { children: crmComposer ? _jsx(StrokeIcon, { name: "smile", size: 18 }) : EmojiIcon })), showMediaUpload && (_jsxs(_Fragment, { children: [_jsx(Upload, { accept: "image/jpeg, image/png, image/jpg, video/*", beforeUpload: beforeUploadImagesAndVideo, multiple: true, onChange: handleChange, showUploadList: false, fileList: listUploadFiles, children: _jsx(Button, Object.assign({ type: "text", shape: "default", className: btnClass }, crmLabel("composer_attach_image"), { children: crmComposer ? (_jsx(StrokeIcon, { name: "image", size: 18 })) : (_jsx(Icon, { icon: "image-02-o", size: 22 })) })) }), _jsx(Upload, { accept: ".doc,.docx,.pdf", beforeUpload: beforeUploadFile, onChange: handleChange, showUploadList: false, fileList: listUploadFiles, children: _jsx(Button, Object.assign({ type: "text", shape: "default", className: btnClass }, crmLabel("composer_attach_file"), { children: crmComposer ? _jsx(StrokeIcon, { name: "paperclip", size: 18 }) : AttachIcon })) })] })), showEmojiPicker && (_jsx(EmojiPicker, { onEmojiSelect: handleEmojiSelect, onClose: () => setShowEmojiPicker(false) }))] }));
|
|
108
|
+
: "bg-[var(--dc-color-primary-light)] text-[var(--dc-color-primary)]")), onClick: () => setShowEmojiPicker(!showEmojiPicker) }, crmLabel("composer_emoji"), { children: crmComposer ? _jsx(StrokeIcon, { name: "smile", size: 18 }) : EmojiIcon })), showMediaUpload && (_jsxs(_Fragment, { children: [_jsx(Upload, { accept: "image/jpeg, image/png, image/jpg, video/*", beforeUpload: beforeUploadImagesAndVideo, multiple: true, onChange: handleChange, showUploadList: false, fileList: listUploadFiles, children: _jsx(Button, Object.assign({ type: "text", shape: "default", className: btnClass }, crmLabel("composer_attach_image"), { children: crmComposer ? (_jsx(StrokeIcon, { name: "image", size: 18 })) : (_jsx(Icon, { icon: "image-02-o", size: 22 })) })) }), _jsx(Upload, { accept: ".doc,.docx,.pdf", beforeUpload: beforeUploadFile, onChange: handleChange, showUploadList: false, fileList: listUploadFiles, children: _jsx(Button, Object.assign({ type: "text", shape: "default", className: btnClass }, crmLabel("composer_attach_file"), { children: crmComposer ? _jsx(StrokeIcon, { name: "paperclip", size: 18 }) : AttachIcon })) })] })), showEmojiPicker && (_jsx(EmojiPicker, { className: crmComposer ? "max-lg:w-80" : undefined, onEmojiSelect: handleEmojiSelect, onClose: () => setShowEmojiPicker(false) }))] }));
|
|
109
109
|
}
|
|
@@ -105,7 +105,7 @@ export const ToolbarPlugin = ({ compact = false }) => {
|
|
|
105
105
|
editor.dispatchCommand(TOGGLE_LINK_COMMAND, "https://");
|
|
106
106
|
}, [editor]);
|
|
107
107
|
const getButtonClasses = (isActive) => {
|
|
108
|
-
return `w-8 h-8 p-0 border-sm ${isActive
|
|
108
|
+
return `w-8 h-8 p-0 border-sm ${compact ? "touch:min-h-10 touch:min-w-10" : ""} ${isActive
|
|
109
109
|
? "bg-blue-100 text-blue-600"
|
|
110
110
|
: "text-gray-500 hover:text-gray-700 hover:bg-gray-100"}`;
|
|
111
111
|
};
|
|
@@ -95,7 +95,7 @@ const MentionMenu = ({ groupID, isBotThread }) => {
|
|
|
95
95
|
// overlapped the composer's own top portion. MentionMenuOffset
|
|
96
96
|
// pushes the extra distance from the caret up to the composer's
|
|
97
97
|
// actual top edge, so the menu clears the input entirely.
|
|
98
|
-
_jsxs(MentionMenuOffset, { "data-cp-name": "MentionMenu", className: "absolute left-0 z-50 max-h-[220px] w-[260px] overflow-y-auto rounded-md border border-gray-200 bg-white py-1 shadow-lg", children: [_jsx("div", { className: "px-3 py-1 text-xs font-medium text-gray-400", children: t("mention.menu_title") }), typeaheadOptions.length === 0 ? (_jsx("div", { className: "px-3 py-2 text-sm text-gray-500", children: limitReached
|
|
98
|
+
_jsxs(MentionMenuOffset, { "data-cp-name": "MentionMenu", className: "absolute left-0 z-50 max-h-[220px] touch:max-h-[min(220px,calc(var(--dc-desk-height,100dvh)-var(--dc-composer-reserve,280px)))] w-[260px] overflow-y-auto rounded-md border border-gray-200 bg-white py-1 shadow-lg", children: [_jsx("div", { className: "px-3 py-1 text-xs font-medium text-gray-400", children: t("mention.menu_title") }), typeaheadOptions.length === 0 ? (_jsx("div", { className: "px-3 py-2 text-sm text-gray-500", children: limitReached
|
|
99
99
|
? t("mention.limit_reached", { max: MAX_MENTIONED_USERS })
|
|
100
100
|
: t("mention.no_result") })) : (typeaheadOptions.map((option, index) => (_jsxs("button", { type: "button", className: `flex w-full items-center gap-2 px-3 py-2 text-left text-sm ${index === selectedIndex ? "bg-blue-50" : "hover:bg-gray-50"}`, onMouseEnter: () => setHighlightedIndex(index), onClick: () => selectOptionAndCleanUp(option), children: [option.option.isAtAll ? (_jsx("span", { className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-gray-100 text-gray-500", children: "@" })) : isCrm ? (_jsx(TintedAvatar, { name: option.option.displayName, src: option.option.faceURL, size: 24 })) : (_jsx(Avatar, { size: 24, src: option.option.faceURL, children: option.option.displayName.charAt(0) })), _jsx("span", { className: "min-w-0 flex-1 truncate", children: option.option.displayName })] }, option.key))))] }), anchorElementRef.current);
|
|
101
101
|
} }));
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { Icon } from "../../components/icon";
|
|
3
3
|
import { StrokeIcon } from "../../components/icon/StrokeIcon";
|
|
4
4
|
/** Classes of a header icon button; an open panel gets the Primary-25 tile in CRM. */
|
|
5
|
-
export const headerIconButtonClass = (isCrm, isOpen) => `${isCrm ? "w-9 h-9 [@container(max-width:699px)]:!w-8 [@container(max-width:699px)]:!h-8" : "w-8 h-8"} p-0 ${isCrm && isOpen
|
|
5
|
+
export const headerIconButtonClass = (isCrm, isOpen) => `${isCrm ? "w-9 h-9 [@container(max-width:699px)]:!w-8 [@container(max-width:699px)]:!h-8 touch:min-h-10 touch:min-w-10" : "w-8 h-8"} p-0 ${isCrm && isOpen
|
|
6
6
|
? "bg-primary-25 text-primary-500"
|
|
7
7
|
: "text-[var(--dc-color-header-icon)]"}`;
|
|
8
8
|
/** Mockup line icon in CRM, the icon-font glyph elsewhere. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageMoreButton.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/MessageMoreButton.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"MessageMoreButton.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/MessageMoreButton.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAsCtC,UAAU,sBAAsB;IAC9B,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,MAAM,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,oFAAoF;AACpF,QAAA,MAAM,iBAAiB,GAAI,mDAMxB,sBAAsB,4CAmFxB,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useRef } from "react";
|
|
4
|
-
import { Dropdown } from "antd";
|
|
4
|
+
import { Dropdown, Menu } from "antd";
|
|
5
5
|
import clsx from "clsx";
|
|
6
6
|
import { StrokeIcon } from "../../../components/icon/StrokeIcon";
|
|
7
7
|
import { useTranslation } from "react-i18next";
|
|
8
8
|
import { useEscapeLayer } from "../../../hooks/common/useEscapeLayer";
|
|
9
|
+
import BottomSheet from "../../../components/common/BottomSheet";
|
|
10
|
+
import { LAYOUT_MEDIA } from "../../../constants/layout";
|
|
9
11
|
// Compact text menu from the design: 260px, 36px rows, 14px text, 18px icons.
|
|
10
12
|
const MORE_MENU_CLASSNAME = clsx("[&_.ant-dropdown-menu]:!w-[260px]", "[&_.ant-dropdown-menu]:!rounded-xl", "[&_.ant-dropdown-menu]:!p-1", "[&_.ant-dropdown-menu-item]:!h-9", "[&_.ant-dropdown-menu-item]:!rounded-lg", "[&_.ant-dropdown-menu-item]:!px-3", "[&_.ant-dropdown-menu-item]:!py-0", "[&_.ant-dropdown-menu-item]:flex", "[&_.ant-dropdown-menu-item]:items-center", "[&_[data-cp-name=ToolboxMenuRow]]:gap-2.5", "[&_[data-cp-name=ToolboxMenuRow]_span]:!text-sm", "[&_[data-cp-name=ToolboxMenuRow]_span]:!font-normal", "[&_[data-cp-name=ToolboxMenuRow]_svg]:!h-[18px]", "[&_[data-cp-name=ToolboxMenuRow]_svg]:!w-[18px]");
|
|
13
|
+
// Sheet rows: 48px, borderless, same labeled items as the dropdown.
|
|
14
|
+
const SHEET_MENU_CLASSNAME = clsx("!border-0", "[&_.ant-menu-item]:!h-12", "[&_.ant-menu-item]:!leading-[48px]", "[&_.ant-menu-item]:!rounded-lg", "[&_.ant-menu-item]:!px-3", "[&_.ant-menu-item]:!m-0", "[&_.ant-menu-item]:!w-full", "[&_[data-cp-name=ToolboxMenuRow]]:gap-3");
|
|
11
15
|
/** CRM only: "…" beside the bubble that opens the same text menu as right-click. */
|
|
12
16
|
const MessageMoreButton = ({ items, open, onOpenChange, isMine, reachable, }) => {
|
|
13
17
|
const { t } = useTranslation();
|
|
14
18
|
const buttonRef = useRef(null);
|
|
15
19
|
useEscapeLayer(open, () => onOpenChange(false));
|
|
20
|
+
// A plain matchMedia read per render, no per-row subscription.
|
|
21
|
+
const isPhoneTier = typeof window !== "undefined" && window.matchMedia(LAYOUT_MEDIA.phone).matches;
|
|
22
|
+
const asSheet = open && isPhoneTier;
|
|
23
|
+
// Mounted on first sheet use only, so rows that never open one carry no Drawer.
|
|
24
|
+
const sheetUsedRef = useRef(false);
|
|
25
|
+
if (asSheet)
|
|
26
|
+
sheetUsedRef.current = true;
|
|
16
27
|
// Opened from the keyboard: move into the menu; closing returns focus to the button.
|
|
17
28
|
const openedByKeyboardRef = useRef(false);
|
|
18
29
|
useEffect(() => {
|
|
@@ -25,7 +36,9 @@ const MessageMoreButton = ({ items, open, onOpenChange, isMine, reachable, }) =>
|
|
|
25
36
|
// The popup mounts a frame or two after `open`; retry briefly.
|
|
26
37
|
let tries = 0;
|
|
27
38
|
const id = window.setInterval(() => {
|
|
28
|
-
const item = document.querySelector(
|
|
39
|
+
const item = document.querySelector(asSheet
|
|
40
|
+
? ".ant-drawer-open [role=menuitem]"
|
|
41
|
+
: ".ant-dropdown:not(.ant-dropdown-hidden) [role=menuitem]");
|
|
29
42
|
item === null || item === void 0 ? void 0 : item.focus();
|
|
30
43
|
if (item || ++tries > 20)
|
|
31
44
|
window.clearInterval(id);
|
|
@@ -36,7 +49,7 @@ const MessageMoreButton = ({ items, open, onOpenChange, isMine, reachable, }) =>
|
|
|
36
49
|
openedByKeyboardRef.current = false;
|
|
37
50
|
(_b = buttonRef.current) === null || _b === void 0 ? void 0 : _b.focus();
|
|
38
51
|
}
|
|
39
|
-
}, [open]);
|
|
40
|
-
return (_jsx(Dropdown, { menu: { items }, trigger: ["click"], open: open, onOpenChange: onOpenChange, placement: isMine ? "bottomRight" : "bottomLeft", overlayClassName: MORE_MENU_CLASSNAME, children: _jsx("button", { ref: buttonRef, type: "button", "data-testid": "message-more-button", "aria-label": t("message_actions"), title: t("message_actions"), "aria-haspopup": "menu", "aria-expanded": open, tabIndex: reachable || open ? 0 : -1, className: clsx("absolute top-1/2 z-[1] flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-lg border-0 bg-gray-5 p-0 text-gray-900 opacity-0 transition-opacity hover:bg-gray-25 focus-visible:opacity-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200 group-hover/msg:opacity-100 group-focus-within/msg:opacity-100", open && "opacity-100", isMine ? "right-full mr-1" : "left-full ml-1"), children: _jsx(StrokeIcon, { name: "more", size: 18 }) }) }));
|
|
52
|
+
}, [open, asSheet]);
|
|
53
|
+
return (_jsxs(_Fragment, { children: [_jsx(Dropdown, { menu: { items }, trigger: ["click"], open: open && !asSheet, onOpenChange: onOpenChange, placement: isMine ? "bottomRight" : "bottomLeft", overlayClassName: MORE_MENU_CLASSNAME, children: _jsx("button", { ref: buttonRef, type: "button", "data-testid": "message-more-button", "aria-label": t("message_actions"), title: t("message_actions"), "aria-haspopup": isPhoneTier ? "dialog" : "menu", "aria-expanded": open, tabIndex: reachable || open ? 0 : -1, className: clsx("absolute top-1/2 z-[1] flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-lg border-0 bg-gray-5 p-0 text-gray-900 opacity-0 transition-opacity hover:bg-gray-25 focus-visible:opacity-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200 group-hover/msg:opacity-100 group-focus-within/msg:opacity-100 touch-any:opacity-100 touch:min-h-10 touch:min-w-10", open && "opacity-100", isMine ? "right-full mr-1" : "left-full ml-1"), children: _jsx(StrokeIcon, { name: "more", size: 18 }) }) }), sheetUsedRef.current && (_jsx(BottomSheet, { open: asSheet, title: t("message_actions"), onClose: () => onOpenChange(false), children: _jsx(Menu, { items: items, selectable: false, onClick: () => onOpenChange(false), className: SHEET_MENU_CLASSNAME }) }))] }));
|
|
41
54
|
};
|
|
42
55
|
export default MessageMoreButton;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QuoteMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/QuoteMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"QuoteMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/QuoteMessage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAK3D,UAAU,qBAAqB;IAC7B,OAAO,EAAE,WAAW,CAAC;IACrB,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED,QAAA,MAAM,gBAAgB,GAAI,mCAGvB,qBAAqB,mDAoBvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -1,62 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useTranslation } from "react-i18next";
|
|
3
|
-
import { useCallback, useMemo } from "react";
|
|
4
|
-
import useAuthStore from "../../../store/auth";
|
|
5
|
-
import useConversationStore from "../../../store/conversation";
|
|
6
3
|
import ReplyQuoteContent from "../../../components/message/reply/ReplyQuoteContent";
|
|
7
|
-
import {
|
|
8
|
-
import { isSupportSessionAgentView } from "../../../utils/conversation";
|
|
4
|
+
import { useQuotedSenderName } from "../../../hooks/message/useQuotedSenderName";
|
|
9
5
|
const QuoteMessageItem = ({ message, onPressQuoteMessage, }) => {
|
|
10
6
|
var _a, _b;
|
|
11
|
-
const userID = useAuthStore((state) => state.userID);
|
|
12
|
-
const isCrm = useAuthStore((state) => state.isCrm);
|
|
13
|
-
const conversationData = useConversationStore((state) => state.conversationData);
|
|
14
7
|
const { t } = useTranslation();
|
|
15
|
-
const isChatSupport = useMemo(() => {
|
|
16
|
-
var _a, _b, _c;
|
|
17
|
-
try {
|
|
18
|
-
return (_c = (_b = (_a = JSON.parse((conversationData === null || conversationData === void 0 ? void 0 : conversationData.ex) || "{}")) === null || _a === void 0 ? void 0 : _a.sessionInfo) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.botId;
|
|
19
|
-
}
|
|
20
|
-
catch (_d) {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
}, [conversationData === null || conversationData === void 0 ? void 0 : conversationData.ex]);
|
|
24
8
|
const quoteMessage = ((_a = message === null || message === void 0 ? void 0 : message.quoteElem) === null || _a === void 0 ? void 0 : _a.quoteMessage) || ((_b = message === null || message === void 0 ? void 0 : message.atTextElem) === null || _b === void 0 ? void 0 : _b.quoteMessage);
|
|
25
|
-
|
|
26
|
-
// owner keeps seeing the thread's own name.
|
|
27
|
-
const isAgentView = !isCrm && isSupportSessionAgentView(conversationData, userID);
|
|
28
|
-
const quotedUsername = useUserUsername(isAgentView && (quoteMessage === null || quoteMessage === void 0 ? void 0 : quoteMessage.sendID) !== userID
|
|
29
|
-
? quoteMessage === null || quoteMessage === void 0 ? void 0 : quoteMessage.sendID
|
|
30
|
-
: undefined);
|
|
31
|
-
const getDisplayName = useCallback(({ name, id }) => {
|
|
32
|
-
if (isAgentView) {
|
|
33
|
-
if (id === userID)
|
|
34
|
-
return t("you");
|
|
35
|
-
return quotedUsername || name || "";
|
|
36
|
-
}
|
|
37
|
-
if (!name)
|
|
38
|
-
return "";
|
|
39
|
-
if (!isCrm && isChatSupport) {
|
|
40
|
-
return conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName;
|
|
41
|
-
}
|
|
42
|
-
if (id === userID)
|
|
43
|
-
return t("you");
|
|
44
|
-
return name;
|
|
45
|
-
}, [
|
|
46
|
-
isAgentView,
|
|
47
|
-
quotedUsername,
|
|
48
|
-
isCrm,
|
|
49
|
-
isChatSupport,
|
|
50
|
-
conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName,
|
|
51
|
-
userID,
|
|
52
|
-
t,
|
|
53
|
-
]);
|
|
9
|
+
const { isMe, name } = useQuotedSenderName(quoteMessage);
|
|
54
10
|
if (!quoteMessage)
|
|
55
11
|
return null;
|
|
56
|
-
const title =
|
|
57
|
-
name: quoteMessage.senderNickname,
|
|
58
|
-
id: quoteMessage.sendID,
|
|
59
|
-
});
|
|
12
|
+
const title = isMe ? t("you") : name;
|
|
60
13
|
return (_jsx("div", { className: "flex cursor-pointer items-center overflow-hidden rounded-r-xl bg-white/70", onClick: () => onPressQuoteMessage === null || onPressQuoteMessage === void 0 ? void 0 : onPressQuoteMessage(quoteMessage.clientMsgID || ""), "data-cp-name": "QuoteMessageItem", children: _jsx(ReplyQuoteContent, { message: quoteMessage, title: title }) }));
|
|
61
14
|
};
|
|
62
15
|
export default QuoteMessageItem;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReplyPreviewBar.d.ts","sourceRoot":"","sources":["../../../../src/components/message/reply/ReplyPreviewBar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ReplyPreviewBar.d.ts","sourceRoot":"","sources":["../../../../src/components/message/reply/ReplyPreviewBar.tsx"],"names":[],"mappings":"AAMA,eAAO,MAAM,eAAe,sDAuC3B,CAAC;AAEF,eAAe,eAAe,CAAC"}
|