@droppii-org/chat-sdk 0.7.3 → 0.7.5
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/assets/images/defaultAvatarGroup.png +0 -0
- 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 +5 -10
- package/dist/components/conversation/ConversationBySessionItem.d.ts.map +1 -1
- package/dist/components/conversation/ConversationBySessionItem.js +6 -11
- 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/ConversationPeerAvatar.d.ts.map +1 -1
- package/dist/components/conversation-inbox/ConversationPeerAvatar.js +3 -1
- 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/conversation-inbox/contact-search/PublicGroupResultItem.d.ts.map +1 -1
- package/dist/components/conversation-inbox/contact-search/PublicGroupResultItem.js +3 -2
- package/dist/components/conversation-inbox/contact-search/constants.d.ts +0 -1
- package/dist/components/conversation-inbox/contact-search/constants.d.ts.map +1 -1
- package/dist/components/conversation-inbox/contact-search/constants.js +0 -2
- package/dist/components/conversation-inbox/contact-search/index.d.ts +0 -1
- package/dist/components/conversation-inbox/contact-search/index.d.ts.map +1 -1
- package/dist/components/conversation-inbox/contact-search/index.js +0 -1
- package/dist/components/group/GroupAvatar.d.ts +9 -0
- package/dist/components/group/GroupAvatar.d.ts.map +1 -0
- package/dist/components/group/GroupAvatar.js +13 -0
- package/dist/components/group/GroupPanelHeader.js +1 -1
- package/dist/components/group/JoinGroupConfirmModal.d.ts.map +1 -1
- package/dist/components/group/JoinGroupConfirmModal.js +3 -2
- 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 +11 -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 +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 +5 -5
- package/dist/components/search-conversation/item/SearchItemAsMessage.d.ts.map +1 -1
- package/dist/components/search-conversation/item/SearchItemAsMessage.js +13 -1
- 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/GroupInfoBodyCrm.d.ts +0 -2
- package/dist/components/thread/GroupInfoBodyCrm.d.ts.map +1 -1
- package/dist/components/thread/GroupInfoBodyCrm.js +2 -2
- package/dist/components/thread/GroupThreadInfo.d.ts.map +1 -1
- package/dist/components/thread/GroupThreadInfo.js +2 -2
- 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/images.d.ts +1 -0
- package/dist/constants/images.d.ts.map +1 -1
- package/dist/constants/images.js +3 -0
- 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 +6 -7
- 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/components/conversation-inbox/contact-search/PublicGroupAvatar.d.ts +0 -9
- package/dist/components/conversation-inbox/contact-search/PublicGroupAvatar.d.ts.map +0 -1
- package/dist/components/conversation-inbox/contact-search/PublicGroupAvatar.js +0 -19
- package/dist/components/group/GroupCompositeAvatar.d.ts +0 -11
- package/dist/components/group/GroupCompositeAvatar.d.ts.map +0 -1
- package/dist/components/group/GroupCompositeAvatar.js +0 -87
- 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
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import { Button } from "antd";
|
|
5
|
+
import { useTranslation } from "react-i18next";
|
|
6
|
+
import BootProgressBar from "../../components/boot/BootProgressBar";
|
|
7
|
+
const SEGMENTS = ["engine", "connect", "sync"];
|
|
8
|
+
const DOT_DELAYS = ["0ms", "160ms", "320ms"];
|
|
9
|
+
const segmentMode = (segment, boot) => {
|
|
10
|
+
const current = SEGMENTS.indexOf(boot.phase);
|
|
11
|
+
const index = SEGMENTS.indexOf(segment);
|
|
12
|
+
if (index < current)
|
|
13
|
+
return "complete";
|
|
14
|
+
if (index > current)
|
|
15
|
+
return "pending";
|
|
16
|
+
// Core only reports sync progress on a fresh device; otherwise the last bar just runs.
|
|
17
|
+
return segment === "sync" && boot.syncProgress > 0 ? "progress" : "indeterminate";
|
|
18
|
+
};
|
|
19
|
+
/** Chat bubble with the "typing" dots while loading, or a "!" when loading failed. */
|
|
20
|
+
const TypingBubble = ({ isError }) => (_jsxs("div", { "aria-hidden": "true", className: clsx("relative mb-2 flex h-[50px] w-16 items-center justify-center gap-1.5 rounded-2xl", isError ? "bg-danger-25" : "bg-[var(--dc-color-primary-light)]"), children: [_jsx("span", { className: "absolute -bottom-1.5 left-3 h-3.5 w-3.5 rotate-45 rounded-sm bg-inherit" }), isError ? (_jsx("span", { className: "relative text-xl font-bold leading-none text-danger-500", children: "!" })) : (DOT_DELAYS.map((delay) => (_jsx("span", { className: "relative h-2 w-2 rounded-full bg-[var(--dc-color-primary)] motion-safe:animate-[dchat-boot-typing_1.2s_ease-in-out_infinite]", style: { animationDelay: delay } }, delay))))] }));
|
|
21
|
+
/**
|
|
22
|
+
* "Đang tải tin nhắn" block shown above the inbox skeleton until the list first loads.
|
|
23
|
+
* Three bars, one per boot step; no percentage text (PO decision for end-customer apps).
|
|
24
|
+
*/
|
|
25
|
+
const InboxBootStatus = ({ boot }) => {
|
|
26
|
+
const { t } = useTranslation("boot");
|
|
27
|
+
if (boot.phase === "ready")
|
|
28
|
+
return null;
|
|
29
|
+
const isError = boot.phase === "error";
|
|
30
|
+
const title = isError ? t("inbox.error_title") : t("inbox.title");
|
|
31
|
+
const detail = isError ? t("inbox.error_hint") : t(`inbox.${boot.phase}`);
|
|
32
|
+
return (_jsxs("div", { "data-cp-name": "InboxBootStatus", "data-phase": boot.phase, className: clsx("flex flex-col items-center gap-2 px-6 pb-4 pt-7 text-center transition-opacity duration-200", !boot.isStatusVisible && "opacity-0"), children: [_jsx("p", { role: "status", "aria-live": "polite", className: "sr-only", children: boot.isStatusVisible ? `${title}. ${detail}` : "" }), _jsx(TypingBubble, { isError: isError }), _jsx("p", { "aria-hidden": "true", className: "text-base font-semibold text-gray-900", children: title }), _jsx("p", { "aria-hidden": "true", className: "min-h-[1.5em] text-sm text-gray-500", children: detail }), isError ? (_jsx(Button, { type: "primary", className: "mt-2", onClick: () => window.location.reload(), children: t("retry") })) : (_jsx("div", { className: "mt-1 flex w-[168px] max-w-full gap-1", children: SEGMENTS.map((segment) => (_jsx(BootProgressBar, { className: "flex-1", mode: segmentMode(segment, boot), value: boot.syncProgress, label: t("sync_progress_label") }, segment))) })), boot.isSlow && !isError && (_jsx("p", { className: "mt-1.5 rounded-lg bg-warning-25 px-3 py-2 text-[13px] leading-normal text-warning-900", children: t("inbox.slow") }))] }));
|
|
33
|
+
};
|
|
34
|
+
export default InboxBootStatus;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Placeholder rows shaped like the inbox ThreadCard, shown until the list has loaded once. */
|
|
2
|
+
declare const InboxListSkeleton: ({ rows }: {
|
|
3
|
+
rows: number;
|
|
4
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export default InboxListSkeleton;
|
|
6
|
+
//# sourceMappingURL=InboxListSkeleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InboxListSkeleton.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/InboxListSkeleton.tsx"],"names":[],"mappings":"AAOA,+FAA+F;AAC/F,QAAA,MAAM,iBAAiB,GAAI,UAAU;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,4CAyBpD,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
const TITLE_WIDTHS = ["w-2/5", "w-1/2", "w-1/3"];
|
|
5
|
+
const PREVIEW_WIDTHS = ["w-4/5", "w-3/5", "w-2/3"];
|
|
6
|
+
/** Placeholder rows shaped like the inbox ThreadCard, shown until the list has loaded once. */
|
|
7
|
+
const InboxListSkeleton = ({ rows }) => (_jsx("div", { "aria-hidden": "true", "data-testid": "inbox-list-skeleton", children: Array.from({ length: rows }, (_, index) => (_jsxs("div", { className: "flex items-start gap-2 border-b border-gray-25 p-3", children: [_jsx("span", { className: "h-12 w-12 shrink-0 rounded-full bg-neutral-200 motion-safe:animate-pulse" }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-2 pt-1", children: [_jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { className: clsx("h-3.5 rounded bg-neutral-200 motion-safe:animate-pulse", TITLE_WIDTHS[index % TITLE_WIDTHS.length]) }), _jsx("span", { className: "ml-auto h-3 w-9 rounded bg-neutral-200 motion-safe:animate-pulse" })] }), _jsx("span", { className: clsx("h-3 rounded bg-neutral-200 motion-safe:animate-pulse", PREVIEW_WIDTHS[index % PREVIEW_WIDTHS.length]) })] })] }, index))) }));
|
|
8
|
+
export default InboxListSkeleton;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PublicGroupResultItem.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/PublicGroupResultItem.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"PublicGroupResultItem.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/PublicGroupResultItem.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAK1E,UAAU,0BAA0B;IAClC,KAAK,EAAE,qBAAqB,CAAC;IAC7B,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,QAAA,MAAM,qBAAqB,GAAI,oBAG5B,0BAA0B,4CA4E5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -4,7 +4,8 @@ import clsx from "clsx";
|
|
|
4
4
|
import { Spin } from "antd";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
6
|
import { useJoinPublicGroup } from "../../../hooks/group/useJoinPublicGroup";
|
|
7
|
-
import
|
|
7
|
+
import GroupAvatar from "../../../components/group/GroupAvatar";
|
|
8
|
+
import { CONTACT_SEARCH_AVATAR_SIZE } from "./constants";
|
|
8
9
|
const PublicGroupResultItem = ({ group, onOpen, }) => {
|
|
9
10
|
var _a, _b;
|
|
10
11
|
const { t } = useTranslation("conversation-inbox");
|
|
@@ -17,7 +18,7 @@ const PublicGroupResultItem = ({ group, onOpen, }) => {
|
|
|
17
18
|
}
|
|
18
19
|
joinGroup({ groupID: group.groupID }, { onSuccess: () => onOpen(group.groupID) });
|
|
19
20
|
};
|
|
20
|
-
return (_jsxs("div", { "data-cp-name": "PublicGroupResultItem", "data-testid": `contact-search-public-group-${group.groupID}`, className: "flex items-center gap-2 border-b border-gray-25 bg-white p-3", children: [_jsxs("button", { type: "button", className: "flex min-w-0 flex-1 items-center gap-2 text-left", onClick: () => onOpen(group.groupID), children: [_jsx(
|
|
21
|
+
return (_jsxs("div", { "data-cp-name": "PublicGroupResultItem", "data-testid": `contact-search-public-group-${group.groupID}`, className: "flex items-center gap-2 border-b border-gray-25 bg-white p-3", children: [_jsxs("button", { type: "button", className: "flex min-w-0 flex-1 items-center gap-2 text-left", onClick: () => onOpen(group.groupID), children: [_jsx(GroupAvatar, { faceURL: group.faceURL, groupName: group.groupName, size: CONTACT_SEARCH_AVATAR_SIZE, className: "shrink-0" }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-1 pb-0.5", children: [_jsx("span", { className: "truncate text-[16px] font-medium leading-[1.6] text-black", children: group.groupName }), _jsxs("span", { className: "flex min-w-0 flex-col text-[14px] leading-[1.6] tracking-[0.14px] text-gray-600", children: [_jsx("span", { className: "truncate", children: t("contact_search.member_count", {
|
|
21
22
|
count: (_a = group.memberCount) !== null && _a !== void 0 ? _a : 0,
|
|
22
23
|
}) }), _jsx("span", { className: "truncate", children: ((_b = group.introduction) === null || _b === void 0 ? void 0 : _b.trim()) ||
|
|
23
24
|
t("contact_search.public_group_fallback") })] })] })] }), _jsxs("button", { type: "button", disabled: isPending, "data-testid": `contact-search-public-group-action-${group.groupID}`, className: clsx("flex h-7 shrink-0 items-center justify-center gap-2 rounded-lg px-3", "whitespace-nowrap text-center text-[12px] font-medium leading-[1.6] tracking-[0.12px]", group.isJoined
|
|
@@ -2,7 +2,6 @@ import { ContactSearchType } from "../../../types/dto";
|
|
|
2
2
|
export declare const CONTACT_SEARCH_DEBOUNCE_MS = 300;
|
|
3
3
|
export declare const CONTACT_SEARCH_ICON_SIZE = 18;
|
|
4
4
|
export declare const CONTACT_SEARCH_AVATAR_SIZE = 48;
|
|
5
|
-
export declare const PUBLIC_GROUP_STACKED_AVATAR_SIZE = 33;
|
|
6
5
|
export declare const CONTACT_SEARCH_PREVIEW_LIMIT = 5;
|
|
7
6
|
export declare enum ContactSearchTab {
|
|
8
7
|
All = "ALL",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,eAAO,MAAM,0BAA0B,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAI7C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,oBAAY,gBAAgB;IAC1B,GAAG,QAAQ;IACX,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,SAAS,cAAc;CACxB;AAED,eAAO,MAAM,mBAAmB,EAAE;IAChC,GAAG,EAAE,gBAAgB,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB,EAKA,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE;IACnC,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB,EAKA,CAAC"}
|
|
@@ -2,8 +2,6 @@ import { ContactSearchType } from "../../../types/dto";
|
|
|
2
2
|
export const CONTACT_SEARCH_DEBOUNCE_MS = 300;
|
|
3
3
|
export const CONTACT_SEARCH_ICON_SIZE = 18;
|
|
4
4
|
export const CONTACT_SEARCH_AVATAR_SIZE = 48;
|
|
5
|
-
// The two overlapping circles of the public-group composite avatar.
|
|
6
|
-
export const PUBLIC_GROUP_STACKED_AVATAR_SIZE = 33;
|
|
7
5
|
// `Tất cả` shows a capped preview of the contact section before handing the
|
|
8
6
|
// seller over to the full `Liên hệ` tab.
|
|
9
7
|
export const CONTACT_SEARCH_PREVIEW_LIMIT = 5;
|
|
@@ -6,7 +6,6 @@ export { default as ContactSearchTabs } from "./ContactSearchTabs";
|
|
|
6
6
|
export { default as ContactSearchSectionHeader } from "./ContactSearchSectionHeader";
|
|
7
7
|
export { default as ContactSearchViewMoreBar } from "./ContactSearchViewMoreBar";
|
|
8
8
|
export { default as PublicGroupResultItem } from "./PublicGroupResultItem";
|
|
9
|
-
export { default as PublicGroupAvatar } from "./PublicGroupAvatar";
|
|
10
9
|
export * from "./constants";
|
|
11
10
|
export * from "./utils";
|
|
12
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC"}
|
|
@@ -6,6 +6,5 @@ export { default as ContactSearchTabs } from "./ContactSearchTabs";
|
|
|
6
6
|
export { default as ContactSearchSectionHeader } from "./ContactSearchSectionHeader";
|
|
7
7
|
export { default as ContactSearchViewMoreBar } from "./ContactSearchViewMoreBar";
|
|
8
8
|
export { default as PublicGroupResultItem } from "./PublicGroupResultItem";
|
|
9
|
-
export { default as PublicGroupAvatar } from "./PublicGroupAvatar";
|
|
10
9
|
export * from "./constants";
|
|
11
10
|
export * from "./utils";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface GroupAvatarProps {
|
|
2
|
+
faceURL?: string | null;
|
|
3
|
+
groupName?: string;
|
|
4
|
+
size?: number;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const GroupAvatar: ({ faceURL, groupName, size, className }: GroupAvatarProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default GroupAvatar;
|
|
9
|
+
//# sourceMappingURL=GroupAvatar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GroupAvatar.d.ts","sourceRoot":"","sources":["../../../src/components/group/GroupAvatar.tsx"],"names":[],"mappings":"AAMA,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,QAAA,MAAM,WAAW,GAAI,yCAA8C,gBAAgB,4CAclF,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import clsx from "clsx";
|
|
5
|
+
import { images } from "../../constants/images";
|
|
6
|
+
// DROPPII-30928: a group without a photo (or whose photo fails to load) shows
|
|
7
|
+
// the default group image, replacing the owner + member composite of DROPPII-29976.
|
|
8
|
+
const GroupAvatar = ({ faceURL, groupName, size = 56, className }) => {
|
|
9
|
+
const [failedSrc, setFailedSrc] = useState(null);
|
|
10
|
+
const photo = faceURL && faceURL !== failedSrc ? faceURL : null;
|
|
11
|
+
return (_jsx("img", { src: photo !== null && photo !== void 0 ? photo : images.defaultAvatarGroup, alt: groupName !== null && groupName !== void 0 ? groupName : "", "data-testid": photo ? "group-avatar" : "default-group-avatar", style: { width: size, height: size }, className: clsx("shrink-0 rounded-full object-cover", className), onError: photo ? () => setFailedSrc(photo) : undefined }));
|
|
12
|
+
};
|
|
13
|
+
export default GroupAvatar;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
4
|
import { CrmIcon as Icon } from "../../components/group/crmIcon";
|
|
5
|
-
const ICON_BUTTON = "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-gray-600 hover:bg-gray-5 focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200";
|
|
5
|
+
const ICON_BUTTON = "flex h-8 w-8 touch:min-h-10 touch:min-w-10 shrink-0 items-center justify-center rounded-lg text-gray-600 hover:bg-gray-5 focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200";
|
|
6
6
|
/** CRM side-panel header: 56px bar with an optional back button and a close button. */
|
|
7
7
|
const GroupPanelHeader = ({ title, onClose, onBack, backLabel, }) => {
|
|
8
8
|
const { t } = useTranslation();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JoinGroupConfirmModal.d.ts","sourceRoot":"","sources":["../../../src/components/group/JoinGroupConfirmModal.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"JoinGroupConfirmModal.d.ts","sourceRoot":"","sources":["../../../src/components/group/JoinGroupConfirmModal.tsx"],"names":[],"mappings":"AAUA,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,qBAAqB,GAAI,6EAQ5B,0BAA0B,4CAqE5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Modal,
|
|
3
|
+
import { Modal, Button } from "antd";
|
|
4
4
|
import { useTranslation } from "react-i18next";
|
|
5
5
|
import { Icon } from "../../components/icon";
|
|
6
|
+
import GroupAvatar from "../../components/group/GroupAvatar";
|
|
6
7
|
const MODAL_WIDTH = 390;
|
|
7
8
|
const AVATAR_SIZE = 96;
|
|
8
9
|
const JoinGroupConfirmModal = ({ open, groupName, groupAvatar, memberCount, loading, onConfirm, onClose, }) => {
|
|
@@ -10,6 +11,6 @@ const JoinGroupConfirmModal = ({ open, groupName, groupAvatar, memberCount, load
|
|
|
10
11
|
return (_jsx(Modal, { "data-cp-name": "JoinGroupConfirmModal", open: open, onCancel: onClose, footer: null, closable: false, centered: true, width: MODAL_WIDTH, maskClosable: !loading, keyboard: !loading, styles: {
|
|
11
12
|
content: { padding: 0, overflow: "hidden", borderRadius: 16 },
|
|
12
13
|
body: { padding: 0 },
|
|
13
|
-
}, children: _jsxs("div", { role: "dialog", "aria-label": t("join_group_confirm_title"), className: "flex flex-col bg-white", children: [_jsxs("div", { className: "flex items-center justify-between gap-4 border-b border-gray-25 p-4", children: [_jsx("p", { className: "flex-1 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("join_group_confirm_title") }), _jsx("button", { type: "button", "aria-label": t("close"), className: "shrink-0", onClick: onClose, disabled: loading, children: _jsx(Icon, { icon: "close-o", size: 24 }) })] }), _jsxs("div", { className: "flex flex-col items-center p-4", children: [_jsx(
|
|
14
|
+
}, children: _jsxs("div", { role: "dialog", "aria-label": t("join_group_confirm_title"), className: "flex flex-col bg-white", children: [_jsxs("div", { className: "flex items-center justify-between gap-4 border-b border-gray-25 p-4", children: [_jsx("p", { className: "flex-1 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("join_group_confirm_title") }), _jsx("button", { type: "button", "aria-label": t("close"), className: "shrink-0", onClick: onClose, disabled: loading, children: _jsx(Icon, { icon: "close-o", size: 24 }) })] }), _jsxs("div", { className: "flex flex-col items-center p-4", children: [_jsx(GroupAvatar, { faceURL: groupAvatar || undefined, groupName: groupName, size: AVATAR_SIZE }), _jsxs("div", { className: "flex flex-col items-center gap-1 pt-3 text-center", children: [_jsx("p", { className: "max-w-[280px] truncate text-[18px] font-bold leading-[1.6] text-black", children: groupName }), _jsx("p", { className: "text-[16px] leading-[1.6] tracking-[0.16px] text-gray-600", children: t("member_count", { count: memberCount }) })] })] }), _jsx("div", { className: "px-4 pb-4", children: _jsx(Button, { "data-testid": "join-group-confirm", type: "primary", className: "h-12 w-full !rounded-lg !border-[var(--dc-color-primary)] !bg-[var(--dc-color-primary)] !text-[16px] !font-medium !text-white hover:!border-[var(--dc-color-primary-hover)] hover:!bg-[var(--dc-color-primary-hover)]", onClick: onConfirm, loading: loading, children: t("join_group_confirm_cta") }) })] }) }));
|
|
14
15
|
};
|
|
15
16
|
export default JoinGroupConfirmModal;
|
|
@@ -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,4CAibpB,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";
|
|
@@ -19,7 +20,7 @@ import { useSidePanel } from "../../hooks/common/useSidePanel";
|
|
|
19
20
|
import SearchDrawer from "../../components/search-conversation/SearchDrawer";
|
|
20
21
|
import { isGroupSession, isGroupConversation } from "../../utils/imCommon";
|
|
21
22
|
import { useGroupPermission } from "../../hooks/group/useGroupPermission";
|
|
22
|
-
import
|
|
23
|
+
import GroupAvatar from "../../components/group/GroupAvatar";
|
|
23
24
|
import GroupMembersDrawer from "./GroupMembersDrawer";
|
|
24
25
|
import { useGroupMembers } from "../../hooks/group/useGroupMembers";
|
|
25
26
|
import { useBotSessionOwnerIdentity } from "../../hooks/session/useBotSessionOwnerIdentity";
|
|
@@ -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" }))) : isRealGroup ? (_jsx(GroupAvatar, { faceURL: avatar, 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 = () => {
|