@droppii-org/chat-sdk 0.7.2 → 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 +23 -5
- package/dist/components/conversation-inbox/ConversationInboxItem.d.ts.map +1 -1
- package/dist/components/conversation-inbox/ConversationInboxItem.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/ConsultantChatButton.d.ts +6 -0
- package/dist/components/message/item/ConsultantChatButton.d.ts.map +1 -0
- package/dist/components/message/item/ConsultantChatButton.js +19 -0
- package/dist/components/message/item/CustomMessage.d.ts.map +1 -1
- package/dist/components/message/item/CustomMessage.js +6 -1
- package/dist/components/message/item/EventMessage.d.ts +11 -0
- package/dist/components/message/item/EventMessage.d.ts.map +1 -0
- package/dist/components/message/item/EventMessage.js +28 -0
- 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/item/consultantCta.d.ts +8 -0
- package/dist/components/message/item/consultantCta.d.ts.map +1 -0
- package/dist/components/message/item/consultantCta.js +5 -0
- package/dist/components/message/item/index.d.ts.map +1 -1
- package/dist/components/message/item/index.js +10 -4
- package/dist/components/message/item/otherSenders.d.ts.map +1 -1
- package/dist/components/message/item/otherSenders.js +4 -1
- 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/useConsultantChatNavigation.d.ts +12 -0
- package/dist/hooks/conversation/useConsultantChatNavigation.d.ts.map +1 -0
- package/dist/hooks/conversation/useConsultantChatNavigation.js +94 -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/useMessage.d.ts +1 -1
- package/dist/hooks/message/useMessage.d.ts.map +1 -1
- package/dist/hooks/message/useMessage.js +7 -4
- package/dist/hooks/message/useNewMessageAnnouncement.d.ts.map +1 -1
- package/dist/hooks/message/useNewMessageAnnouncement.js +3 -1
- 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 +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- 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 +2 -1
- package/dist/screens/conversation-detail/index.d.ts.map +1 -1
- package/dist/screens/conversation-detail/index.js +28 -4
- 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 +16 -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 +12 -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/types/customMessage.d.ts +17 -0
- package/dist/types/customMessage.d.ts.map +1 -1
- package/dist/types/customMessage.js +8 -0
- package/dist/utils/common.d.ts +2 -0
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/common.js +14 -4
- 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/dist/utils/customMessage.d.ts +7 -1
- package/dist/utils/customMessage.d.ts.map +1 -1
- package/dist/utils/customMessage.js +55 -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
|
@@ -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;
|
|
@@ -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":"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. */
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
interface ConsultantChatButtonProps {
|
|
2
|
+
onClick: () => void;
|
|
3
|
+
}
|
|
4
|
+
declare const ConsultantChatButton: ({ onClick }: ConsultantChatButtonProps) => import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export default ConsultantChatButton;
|
|
6
|
+
//# sourceMappingURL=ConsultantChatButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConsultantChatButton.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/ConsultantChatButton.tsx"],"names":[],"mappings":"AAMA,UAAU,yBAAyB;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,oBAAoB,GAAI,aAAa,yBAAyB,4CAuBnE,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
import { Icon } from "../../../components/icon";
|
|
6
|
+
const ConsultantChatButton = ({ onClick }) => {
|
|
7
|
+
const { t } = useTranslation();
|
|
8
|
+
// A second click before the thread switches would push the same route twice.
|
|
9
|
+
const [isOpening, setIsOpening] = useState(false);
|
|
10
|
+
return (_jsxs("button", { type: "button", "data-testid": "consultant-chat-button", disabled: isOpening, onClick: (event) => {
|
|
11
|
+
// The bubble underneath toggles its time label on click.
|
|
12
|
+
event.stopPropagation();
|
|
13
|
+
if (isOpening)
|
|
14
|
+
return;
|
|
15
|
+
setIsOpening(true);
|
|
16
|
+
onClick();
|
|
17
|
+
}, className: "flex h-[31px] w-full items-center justify-center gap-2 rounded-lg bg-[var(--dc-color-primary)] px-3 text-[14px] font-normal leading-[160%] text-white transition-colors hover:bg-[var(--dc-color-primary-hover)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--dc-color-primary-focus)]", children: [_jsx(Icon, { icon: "chat-square-o", size: 20, className: "text-white" }), _jsx("span", { children: t("consultant_chat_button") })] }));
|
|
18
|
+
};
|
|
19
|
+
export default ConsultantChatButton;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CustomMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/CustomMessage.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"CustomMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/CustomMessage.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAW3D,UAAU,sBAAsB;IAC9B,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,QAAA,MAAM,iBAAiB,GAAI,aAAa,sBAAsB,mDAiD7D,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -3,7 +3,9 @@ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import clsx from "clsx";
|
|
4
4
|
import { useTranslation } from "react-i18next";
|
|
5
5
|
import { useChatContext } from "../../../context/ChatContext";
|
|
6
|
-
import {
|
|
6
|
+
import { CustomMessageType } from "../../../types/customMessage";
|
|
7
|
+
import { isSystemEventMessage, parseCustomMessagePayload, } from "../../../utils/customMessage";
|
|
8
|
+
import EventMessageItem from "./EventMessage";
|
|
7
9
|
import { MESSAGE_TEXT_CLASS } from "./textStyle";
|
|
8
10
|
const CustomMessageItem = ({ message }) => {
|
|
9
11
|
var _a, _b;
|
|
@@ -14,6 +16,9 @@ const CustomMessageItem = ({ message }) => {
|
|
|
14
16
|
if (renderedContent) {
|
|
15
17
|
return _jsx(_Fragment, { children: renderedContent });
|
|
16
18
|
}
|
|
19
|
+
if (isSystemEventMessage(message)) {
|
|
20
|
+
return (_jsx(EventMessageItem, { message: message, data: (payload === null || payload === void 0 ? void 0 : payload.type) === CustomMessageType.Event ? payload.data : null }));
|
|
21
|
+
}
|
|
17
22
|
const fallbackText = ((_a = message === null || message === void 0 ? void 0 : message.textElem) === null || _a === void 0 ? void 0 : _a.content) || ((_b = message === null || message === void 0 ? void 0 : message.quoteElem) === null || _b === void 0 ? void 0 : _b.text);
|
|
18
23
|
if (fallbackText) {
|
|
19
24
|
return (_jsx("p", { className: clsx("min-w-0 whitespace-pre-wrap [overflow-wrap:anywhere]", MESSAGE_TEXT_CLASS), children: fallbackText }));
|