@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
|
@@ -225,6 +225,7 @@
|
|
|
225
225
|
"join_link_unavailable_message": "Liên kết đã bị thu hồi, thay thế hoặc nhóm không còn tồn tại. Vui lòng liên hệ người gửi để nhận liên kết mới.",
|
|
226
226
|
"join_link_unavailable_action": "Đã hiểu",
|
|
227
227
|
"close": "Đóng",
|
|
228
|
+
"app_menu_open": "Mở menu",
|
|
228
229
|
"leave_group_confirm_title": "Rời khỏi nhóm?",
|
|
229
230
|
"leave_group_confirm_message": "Bạn có chắc chắn muốn rời khỏi nhóm này không?",
|
|
230
231
|
"leave_group_success": "Rời khỏi nhóm thành công",
|
|
@@ -314,7 +315,6 @@
|
|
|
314
315
|
"no_message_yet": "Chưa có tin nhắn",
|
|
315
316
|
"folder_group_collapse": "Thu gọn {{name}}",
|
|
316
317
|
"folder_group_expand": "Mở rộng {{name}}",
|
|
317
|
-
"viewport_too_narrow": "Vui lòng dùng màn hình rộng từ 1024px",
|
|
318
318
|
"thread_info_open": "Thông tin hội thoại",
|
|
319
319
|
"thread_info_close": "Đóng thông tin (Esc)",
|
|
320
320
|
"search_in_conversation": "Tìm trong hội thoại",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation-detail/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/conversation-detail/index.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAWrF,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,6CAA6C,CAAC;AAQrD,MAAM,WAAW,4BACf,SAAQ,4BAA4B,EAClC,4BAA4B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,uBAAuB,GAAI,8IAc9B,4BAA4B,mDA4Q9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -19,6 +19,7 @@ import { useBoolean } from "ahooks";
|
|
|
19
19
|
import clsx from "clsx";
|
|
20
20
|
import { Empty, Spin } from "antd";
|
|
21
21
|
import { Icon } from "../../components/icon";
|
|
22
|
+
import useAuthStore from "../../store/auth";
|
|
22
23
|
import useConversationStore from "../../store/conversation";
|
|
23
24
|
import ThreadProfilePanel from "../../components/conversation-detail/ThreadProfilePanel";
|
|
24
25
|
import MediaResourcePanel from "../../components/media-resources/MediaResourcePanel";
|
|
@@ -30,7 +31,7 @@ import { useBotFlow } from "../../hooks/conversation/useBotFlow";
|
|
|
30
31
|
import { BOT_TYPE } from "../../constants/botFlow";
|
|
31
32
|
import { useResolveConversation, } from "../../hooks/conversation/useResolveConversation";
|
|
32
33
|
import { nextConsultantReturnTarget, useConsultantChatNavigation, } from "../../hooks/conversation/useConsultantChatNavigation";
|
|
33
|
-
import { isBotPeer } from "../../utils/conversation";
|
|
34
|
+
import { isBotPeer, isSupportSessionAgentView } from "../../utils/conversation";
|
|
34
35
|
import { COMPOSER_DISMISS_ZONE_ATTR } from "../../hooks/common/useOutsideTapDismiss";
|
|
35
36
|
const DChatConversationDetail = (_a) => {
|
|
36
37
|
var _b;
|
|
@@ -39,9 +40,10 @@ const DChatConversationDetail = (_a) => {
|
|
|
39
40
|
// inputProps goes to ConversationDetailInput, which has no business with it.
|
|
40
41
|
onCopyMessageLink, onSearchMessageRevoked } = _a, inputProps = __rest(_a, ["className", "children", "onBack", "conversationId", "messageId", "userId", "groupId", "botId", "onCopyMessageLink", "onSearchMessageRevoked"]);
|
|
41
42
|
const { t } = useTranslation("conversation-inbox");
|
|
42
|
-
const { useUrlState = true } = useChatContext();
|
|
43
|
+
const { useUrlState = true, user } = useChatContext();
|
|
43
44
|
const onNavigate = useChatNavigate();
|
|
44
45
|
const conversation = useConversationStore((state) => state.conversationData);
|
|
46
|
+
const authUserID = useAuthStore((state) => state.userID);
|
|
45
47
|
const isViewOnlyMember = useConversationStore((state) => state.isViewOnlyMember);
|
|
46
48
|
const clearSelectedConversation = useConversationStore((state) => state.clearSelectedConversation);
|
|
47
49
|
const setPendingResolveTarget = useConversationStore((state) => state.setPendingResolveTarget);
|
|
@@ -52,7 +54,10 @@ const DChatConversationDetail = (_a) => {
|
|
|
52
54
|
botId,
|
|
53
55
|
messageId,
|
|
54
56
|
});
|
|
55
|
-
|
|
57
|
+
// The bot flow belongs to the session owner; an agent (PDP CS) just chats.
|
|
58
|
+
const isBotThread = !!conversation &&
|
|
59
|
+
isBotPeer(conversation) &&
|
|
60
|
+
!isSupportSessionAgentView(conversation, (user === null || user === void 0 ? void 0 : user.userID) || authUserID);
|
|
56
61
|
const botFlow = useBotFlow({
|
|
57
62
|
conversationId: (_b = conversation === null || conversation === void 0 ? void 0 : conversation.conversationID) !== null && _b !== void 0 ? _b : "",
|
|
58
63
|
isBotThread,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ChatBootState } from "../../hooks/init/useChatBootPhase";
|
|
2
|
+
/** CRM boot status: the three named steps, sync progress, a slow-network note and a retry on failure. */
|
|
3
|
+
declare const DeskBootCard: ({ boot }: {
|
|
4
|
+
boot: ChatBootState;
|
|
5
|
+
}) => import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
+
export default DeskBootCard;
|
|
7
|
+
//# sourceMappingURL=DeskBootCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeskBootCard.d.ts","sourceRoot":"","sources":["../../../src/screens/desk-message/DeskBootCard.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAkEnE,yGAAyG;AACzG,QAAA,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,mDAgFtD,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
import clsx from "clsx";
|
|
5
|
+
import { Button } from "antd";
|
|
6
|
+
import { useTranslation } from "react-i18next";
|
|
7
|
+
import BootProgressBar from "../../components/boot/BootProgressBar";
|
|
8
|
+
import { StrokeIcon } from "../../components/icon/StrokeIcon";
|
|
9
|
+
const STEPS = ["engine", "connect", "sync"];
|
|
10
|
+
/** A fresh device's sync reports 1, 4 and 10 before messages arrive; only higher values say much. */
|
|
11
|
+
const SYNC_PERCENT_MIN = 10;
|
|
12
|
+
const STEP_TEXT_CLASS = {
|
|
13
|
+
done: "text-gray-900",
|
|
14
|
+
active: "font-medium text-gray-900",
|
|
15
|
+
pending: "text-gray-400",
|
|
16
|
+
error: "font-medium text-danger-600",
|
|
17
|
+
};
|
|
18
|
+
const getStepStates = (boot) => {
|
|
19
|
+
var _a;
|
|
20
|
+
const isError = boot.phase === "error";
|
|
21
|
+
const current = STEPS.indexOf((isError ? ((_a = boot.failedStep) !== null && _a !== void 0 ? _a : "engine") : boot.phase));
|
|
22
|
+
return STEPS.map((_, index) => {
|
|
23
|
+
if (index < current)
|
|
24
|
+
return "done";
|
|
25
|
+
if (index > current)
|
|
26
|
+
return "pending";
|
|
27
|
+
return isError ? "error" : "active";
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
const StepMarker = ({ state }) => {
|
|
31
|
+
if (state === "done") {
|
|
32
|
+
return (_jsx("span", { className: "flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-success-400 text-white", children: _jsx(StrokeIcon, { name: "check", size: 11, strokeWidth: 3 }) }));
|
|
33
|
+
}
|
|
34
|
+
if (state === "error") {
|
|
35
|
+
return (_jsx("span", { className: "flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-danger-500 text-[11px] font-bold leading-none text-white", children: "!" }));
|
|
36
|
+
}
|
|
37
|
+
if (state === "active") {
|
|
38
|
+
return (_jsx("span", { className: "h-4 w-4 shrink-0 rounded-full border-2 border-primary-25 border-t-primary-400 motion-safe:animate-spin" }));
|
|
39
|
+
}
|
|
40
|
+
return _jsx("span", { className: "h-4 w-4 shrink-0 rounded-full border-[1.5px] border-gray-100" });
|
|
41
|
+
};
|
|
42
|
+
const BootMark = ({ isError }) => (_jsxs("span", { "aria-hidden": "true", className: "relative flex h-12 w-12 shrink-0", children: [!isError && (_jsx("span", { className: "absolute inset-0 rounded-xl bg-primary-200 motion-safe:animate-[dchat-boot-breathe_2s_ease-out_infinite] motion-reduce:hidden" })), _jsx("span", { className: "relative flex h-12 w-12 items-center justify-center rounded-xl bg-primary-400 text-white", children: _jsx(StrokeIcon, { name: "message-circle", size: 26 }) }), isError && (_jsx("span", { className: "absolute -bottom-1.5 -right-1.5 flex h-[22px] w-[22px] items-center justify-center rounded-full border-2 border-white bg-danger-500 text-xs font-bold leading-none text-white", children: "!" }))] }));
|
|
43
|
+
/** CRM boot status: the three named steps, sync progress, a slow-network note and a retry on failure. */
|
|
44
|
+
const DeskBootCard = ({ boot }) => {
|
|
45
|
+
var _a;
|
|
46
|
+
const { t } = useTranslation("boot");
|
|
47
|
+
const errorRef = useRef(null);
|
|
48
|
+
const isError = boot.phase === "error";
|
|
49
|
+
// Agents work from the keyboard, so Enter should retry; but never pull focus off the rail.
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
var _a, _b;
|
|
52
|
+
if (!isError)
|
|
53
|
+
return;
|
|
54
|
+
const active = document.activeElement;
|
|
55
|
+
if (active && active !== document.body)
|
|
56
|
+
return;
|
|
57
|
+
(_b = (_a = errorRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("button")) === null || _b === void 0 ? void 0 : _b.focus();
|
|
58
|
+
}, [isError]);
|
|
59
|
+
if (boot.phase === "ready")
|
|
60
|
+
return null;
|
|
61
|
+
const title = t(`desk.title.${isError ? "error" : boot.phase}`);
|
|
62
|
+
const errorHint = t("desk.error_hint", {
|
|
63
|
+
step: t(`desk.steps.${(_a = boot.failedStep) !== null && _a !== void 0 ? _a : "engine"}`),
|
|
64
|
+
});
|
|
65
|
+
const stepStates = getStepStates(boot);
|
|
66
|
+
const showPercent = boot.phase === "sync" && boot.syncProgress > SYNC_PERCENT_MIN;
|
|
67
|
+
return (_jsxs("div", { "data-cp-name": "DeskBootCard", "data-phase": boot.phase, className: clsx("flex w-full max-w-[340px] flex-col gap-4 rounded-2xl border border-gray-25 bg-white p-6 shadow-sm transition-opacity duration-200", !boot.isStatusVisible && "opacity-0"), children: [_jsx("p", { role: "status", "aria-live": "polite", className: "sr-only", children: boot.isStatusVisible ? (isError ? `${title}. ${errorHint}` : title) : "" }), _jsx(BootMark, { isError: isError }), _jsx("p", { "aria-hidden": "true", className: "text-lg font-semibold text-gray-900", children: title }), _jsx("ol", { className: "flex flex-col gap-2.5", children: STEPS.map((step, index) => (_jsxs("li", { "aria-current": ["active", "error"].includes(stepStates[index]) ? "step" : undefined, className: clsx("flex items-center gap-2.5 text-sm", STEP_TEXT_CLASS[stepStates[index]]), children: [_jsx(StepMarker, { state: stepStates[index] }), _jsx("span", { className: "flex-1", children: t(`desk.steps.${step}`) }), step === "sync" && showPercent && (_jsxs("span", { className: "text-[13px] font-semibold tabular-nums text-primary-400", children: [boot.syncProgress, "%"] }))] }, step))) }), !isError && (_jsx(BootProgressBar, { mode: boot.phase === "sync" && boot.syncProgress > 0 ? "progress" : "indeterminate", value: boot.syncProgress, label: t("sync_progress_label") })), boot.isSlow && !isError && (_jsx("p", { className: "rounded-lg bg-warning-25 px-3 py-2 text-[13px] leading-normal text-warning-900", children: t("desk.slow") })), isError && (_jsxs("div", { ref: errorRef, className: "flex flex-col gap-3.5", children: [_jsx("p", { "aria-hidden": "true", className: "text-[13px] leading-normal text-gray-600", children: errorHint }), _jsx(Button, { type: "primary", className: "self-start", onClick: () => window.location.reload(), children: t("retry") })] }))] }));
|
|
68
|
+
};
|
|
69
|
+
export default DeskBootCard;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
interface DeskOfflineOverlayProps {
|
|
3
|
+
isPhone: boolean;
|
|
4
|
+
onOpenAppMenu?: (opener: HTMLElement | null) => void;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
/** Covers a locked desk with the reconnect status; on phone it keeps a way to the app menu. */
|
|
8
|
+
declare const DeskOfflineOverlay: ({ isPhone, onOpenAppMenu, children }: DeskOfflineOverlayProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export default DeskOfflineOverlay;
|
|
10
|
+
//# sourceMappingURL=DeskOfflineOverlay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeskOfflineOverlay.d.ts","sourceRoot":"","sources":["../../../src/screens/desk-message/DeskOfflineOverlay.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC,UAAU,uBAAuB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IACrD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,+FAA+F;AAC/F,QAAA,MAAM,kBAAkB,GAAI,sCAAsC,uBAAuB,4CAsBxF,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import { StrokeIcon } from "../../components/icon/StrokeIcon";
|
|
5
|
+
import { DESK_OFFLINE_OVERLAY_ATTR } from "../../hooks/conversation/useDeskOfflineLock";
|
|
6
|
+
/** Covers a locked desk with the reconnect status; on phone it keeps a way to the app menu. */
|
|
7
|
+
const DeskOfflineOverlay = ({ isPhone, onOpenAppMenu, children }) => {
|
|
8
|
+
const { t } = useTranslation();
|
|
9
|
+
return (_jsxs("div", { [DESK_OFFLINE_OVERLAY_ATTR]: "", "data-testid": "desk-offline-overlay", className: "absolute inset-0 z-[1000] flex flex-col items-center justify-center gap-4 bg-white/70 p-4", children: [isPhone && onOpenAppMenu && (_jsx("button", { type: "button", "data-app-menu-button": true, "aria-label": t("app_menu_open"), onClick: (event) => onOpenAppMenu(event.currentTarget), className: "absolute left-2 top-2 flex h-10 w-10 items-center justify-center rounded-lg border-0 bg-transparent p-0 text-gray-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200", children: _jsx(StrokeIcon, { name: "menu", size: 20 }) })), children] }));
|
|
10
|
+
};
|
|
11
|
+
export default DeskOfflineOverlay;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
1
2
|
import { GroupThreadInfoConfig } from "../../components/thread/GroupThreadInfo";
|
|
2
3
|
import type { CannedCreateRequest } from "../../types/chat";
|
|
3
4
|
interface DeskWorkspaceProps {
|
|
@@ -5,8 +6,13 @@ interface DeskWorkspaceProps {
|
|
|
5
6
|
groupThreadInfoConfig?: GroupThreadInfoConfig;
|
|
6
7
|
onCopyMessageLink?: (conversationId: string, clientMsgID: string) => void;
|
|
7
8
|
onSearchMessageRevoked?: () => void;
|
|
9
|
+
onOpenAppMenu?: (opener: HTMLElement | null) => void;
|
|
10
|
+
/** Connection dropped after the first connect: the desk stays visible but can't be used. */
|
|
11
|
+
isOffline?: boolean;
|
|
12
|
+
/** Shown in the offline overlay: reconnect status, and Retry once the reconnect has failed. */
|
|
13
|
+
offlineContent?: ReactNode;
|
|
8
14
|
}
|
|
9
15
|
/** Bright Workspace: folder, list, chat and info as separate white panels on the page canvas. */
|
|
10
|
-
declare const DeskWorkspace: ({ openCreateCannedModal, groupThreadInfoConfig, onCopyMessageLink, onSearchMessageRevoked, }: DeskWorkspaceProps) => import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
declare const DeskWorkspace: ({ openCreateCannedModal, groupThreadInfoConfig, onCopyMessageLink, onSearchMessageRevoked, onOpenAppMenu, isOffline, offlineContent, }: DeskWorkspaceProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
17
|
export default DeskWorkspace;
|
|
12
18
|
//# sourceMappingURL=DeskWorkspace.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeskWorkspace.d.ts","sourceRoot":"","sources":["../../../src/screens/desk-message/DeskWorkspace.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DeskWorkspace.d.ts","sourceRoot":"","sources":["../../../src/screens/desk-message/DeskWorkspace.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAkB5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGxD,UAAU,kBAAkB;IAC1B,qBAAqB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAChE,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IACpC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IACrD,4FAA4F;IAC5F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+FAA+F;IAC/F,cAAc,CAAC,EAAE,SAAS,CAAC;CAC5B;AAID,iGAAiG;AACjG,QAAA,MAAM,aAAa,GAAI,wIAQpB,kBAAkB,4CAiLpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -1,29 +1,38 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback, useEffect, useState } from "react";
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import { useSearchParams } from "next/navigation";
|
|
4
5
|
import MessageList from "../../components/message/MessageList";
|
|
5
6
|
import DeskConversationList from "../../components/conversation/DeskConversationList";
|
|
6
7
|
import DeskAssignedSession from "../../components/session/DeskAssignedSession";
|
|
7
8
|
import ThreadInfo from "../../components/thread/ThreadInfo";
|
|
8
9
|
import { useMediaQuery } from "../../hooks/common/useMediaQuery";
|
|
9
10
|
import { useSidePanel } from "../../hooks/common/useSidePanel";
|
|
11
|
+
import { useVisualViewportHeight } from "../../hooks/common/useVisualViewportHeight";
|
|
12
|
+
import { useViewportTier } from "../../hooks/common/useViewportTier";
|
|
13
|
+
import { useDeskOfflineLock } from "../../hooks/conversation/useDeskOfflineLock";
|
|
14
|
+
import { useDeskThreadNavigation } from "../../hooks/conversation/useDeskThreadNavigation";
|
|
15
|
+
import useSidePanelStore from "../../store/sidePanel";
|
|
10
16
|
import useConversationStore from "../../store/conversation";
|
|
11
17
|
import useDeskPanelHostStore from "../../store/deskPanelHost";
|
|
12
18
|
import useWorkspaceLayoutStore from "../../store/workspaceLayout";
|
|
13
|
-
import { LAYOUT_BREAKPOINTS, LAYOUT_WIDTHS } from "../../constants/layout";
|
|
19
|
+
import { LAYOUT_BREAKPOINTS, LAYOUT_MEDIA, LAYOUT_WIDTHS } from "../../constants/layout";
|
|
14
20
|
import { useDeskShortcuts } from "../../hooks/common/useDeskShortcuts";
|
|
15
21
|
import { useNewMessageAnnouncement } from "../../hooks/message/useNewMessageAnnouncement";
|
|
16
22
|
import ShortcutHelpModal from "../../components/shortcut-help/ShortcutHelpModal";
|
|
17
23
|
import FolderOverlay from "./FolderOverlay";
|
|
18
|
-
import
|
|
24
|
+
import PhoneThreadFallbackHeader from "./PhoneThreadFallbackHeader";
|
|
25
|
+
import DeskOfflineOverlay from "./DeskOfflineOverlay";
|
|
19
26
|
import { PeerType } from "../../types/conversation";
|
|
20
27
|
const minWidth = (px) => `(min-width: ${px}px)`;
|
|
21
28
|
/** Bright Workspace: folder, list, chat and info as separate white panels on the page canvas. */
|
|
22
|
-
const DeskWorkspace = ({ openCreateCannedModal, groupThreadInfoConfig, onCopyMessageLink, onSearchMessageRevoked, }) => {
|
|
29
|
+
const DeskWorkspace = ({ openCreateCannedModal, groupThreadInfoConfig, onCopyMessageLink, onSearchMessageRevoked, onOpenAppMenu, isOffline = false, offlineContent, }) => {
|
|
23
30
|
const selectedConversationId = useConversationStore((state) => state.selectedConversationId);
|
|
24
31
|
const searchClientMsgID = useConversationStore((state) => state.searchClientMsgID);
|
|
25
32
|
const { isOpen: isInfoOpen, toggle: toggleInfo, close: closeInfo } = useSidePanel("info");
|
|
26
|
-
const
|
|
33
|
+
const tier = useViewportTier();
|
|
34
|
+
const isPhone = tier === "phone";
|
|
35
|
+
const isDesktop = tier === "desktop";
|
|
27
36
|
const isFolderInline = useMediaQuery(minWidth(LAYOUT_BREAKPOINTS.folderInline));
|
|
28
37
|
const isInfoInline = useMediaQuery(minWidth(LAYOUT_BREAKPOINTS.infoInline));
|
|
29
38
|
const isSupportPanelInline = useMediaQuery(minWidth(LAYOUT_BREAKPOINTS.supportPanelInline));
|
|
@@ -31,13 +40,67 @@ const DeskWorkspace = ({ openCreateCannedModal, groupThreadInfoConfig, onCopyMes
|
|
|
31
40
|
const isBotThread = useConversationStore((state) => { var _a; return ((_a = state.conversationData) === null || _a === void 0 ? void 0 : _a.peerType) === PeerType.BOT; });
|
|
32
41
|
const sidePanelsInline = isInfoInline && !(isBotThread && isSupportPanelInline);
|
|
33
42
|
const [workspaceEl, setWorkspaceEl] = useState(null);
|
|
43
|
+
// Touch below desktop: size the desk (and sheets) to the visible viewport, keyboard included.
|
|
44
|
+
const isTouch = useMediaQuery(LAYOUT_MEDIA.touch);
|
|
45
|
+
useVisualViewportHeight(workspaceEl, isTouch && tier !== "desktop");
|
|
34
46
|
const [panelSlotEl, setPanelSlotEl] = useState(null);
|
|
35
47
|
useEffect(() => {
|
|
36
48
|
useDeskPanelHostStore
|
|
37
49
|
.getState()
|
|
38
|
-
.setHost({
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
.setHost({
|
|
51
|
+
workspace: workspaceEl,
|
|
52
|
+
slot: panelSlotEl,
|
|
53
|
+
isInline: sidePanelsInline,
|
|
54
|
+
isFullScreen: isPhone,
|
|
55
|
+
});
|
|
56
|
+
}, [workspaceEl, panelSlotEl, sidePanelsInline, isPhone]);
|
|
57
|
+
useEffect(() => () => {
|
|
58
|
+
useDeskPanelHostStore
|
|
59
|
+
.getState()
|
|
60
|
+
.setHost({ workspace: null, slot: null, isFullScreen: false });
|
|
61
|
+
useWorkspaceLayoutStore.getState().setPhonePendingPane(null);
|
|
62
|
+
}, []);
|
|
63
|
+
// Phone shows one pane: the URL thread unless an open/back tap is still settling.
|
|
64
|
+
const urlThreadId = useSearchParams().get("threadId");
|
|
65
|
+
const pendingPane = useWorkspaceLayoutStore((state) => state.phonePendingPane);
|
|
66
|
+
const setPhonePendingPane = useWorkspaceLayoutStore((state) => state.setPhonePendingPane);
|
|
67
|
+
const showThread = pendingPane ? pendingPane === "thread" : Boolean(urlThreadId);
|
|
68
|
+
const { backToList } = useDeskThreadNavigation();
|
|
69
|
+
const hasConversationData = useConversationStore((state) => Boolean(state.conversationData));
|
|
70
|
+
const listPaneRef = useRef(null);
|
|
71
|
+
const chatPaneRef = useRef(null);
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
setPhonePendingPane(null);
|
|
74
|
+
}, [urlThreadId, setPhonePendingPane]);
|
|
75
|
+
// A panel left open from thread A must not cover thread B.
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
if (isPhone)
|
|
78
|
+
useSidePanelStore.getState().closePanel();
|
|
79
|
+
}, [isPhone, selectedConversationId]);
|
|
80
|
+
const wasShowingThread = useRef(showThread);
|
|
81
|
+
useDeskOfflineLock(workspaceEl, isOffline, () => {
|
|
82
|
+
var _a, _b;
|
|
83
|
+
return isPhone
|
|
84
|
+
? showThread
|
|
85
|
+
? (_b = (_a = chatPaneRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("[data-desk-back]")) !== null && _b !== void 0 ? _b : null
|
|
86
|
+
: listPaneRef.current
|
|
87
|
+
: null;
|
|
88
|
+
});
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
var _a, _b, _c;
|
|
91
|
+
if (!isPhone)
|
|
92
|
+
return;
|
|
93
|
+
// Overlays that set the shortcuts-off marker (nav drawer, sheets, offline lock) own focus.
|
|
94
|
+
const navOpen = document.querySelector("[data-desk-shortcuts-off]") !== null;
|
|
95
|
+
if (showThread) {
|
|
96
|
+
if (!navOpen)
|
|
97
|
+
(_b = (_a = chatPaneRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("[data-desk-back]")) === null || _b === void 0 ? void 0 : _b.focus();
|
|
98
|
+
}
|
|
99
|
+
else if (wasShowingThread.current) {
|
|
100
|
+
(_c = listPaneRef.current) === null || _c === void 0 ? void 0 : _c.focus();
|
|
101
|
+
}
|
|
102
|
+
wasShowingThread.current = showThread;
|
|
103
|
+
}, [isPhone, showThread, hasConversationData]);
|
|
41
104
|
const setFolderOverlayOpen = useWorkspaceLayoutStore((state) => state.setFolderOverlayOpen);
|
|
42
105
|
const [isHelpOpen, setIsHelpOpen] = useState(false);
|
|
43
106
|
const openHelp = useCallback(() => setIsHelpOpen(true), []);
|
|
@@ -48,10 +111,16 @@ const DeskWorkspace = ({ openCreateCannedModal, groupThreadInfoConfig, onCopyMes
|
|
|
48
111
|
if (isFolderInline)
|
|
49
112
|
setFolderOverlayOpen(false);
|
|
50
113
|
}, [isFolderInline, setFolderOverlayOpen]);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
return (_jsxs("div", { ref: setWorkspaceEl, className:
|
|
54
|
-
|
|
55
|
-
|
|
114
|
+
const messageList = (_jsx(MessageList, { conversationId: selectedConversationId, searchClientMsgID: searchClientMsgID, openCreateCannedModal: openCreateCannedModal, onOpenThreadInfo: toggleInfo, onCopyMessageLink: onCopyMessageLink, onSearchMessageRevoked: onSearchMessageRevoked, onBack: isPhone ? backToList : undefined, showPinnedMessageBar: true }));
|
|
115
|
+
// One child layout for every tier, so crossing a breakpoint never remounts the panes.
|
|
116
|
+
return (_jsxs("div", { ref: setWorkspaceEl, className: isPhone
|
|
117
|
+
? "relative flex flex-1 h-[var(--dc-desk-height,var(--dc-app-height,100vh))] overflow-hidden bg-white"
|
|
118
|
+
: "relative flex flex-1 flex-row h-[var(--dc-desk-height,var(--dc-app-height,100vh))] gap-2 p-2 overflow-hidden bg-gray-5", "data-cp-name": "DeskWorkspace", children: [_jsx("div", { "aria-live": "polite", role: "status", className: "sr-only", children: announcement }), isFolderInline && _jsx(DeskAssignedSession, {}), _jsxs("div", { ref: listPaneRef, tabIndex: isPhone ? -1 : undefined, className: isPhone
|
|
119
|
+
? `absolute inset-0 overflow-hidden bg-white outline-none ${showThread ? "invisible" : ""}`
|
|
120
|
+
: "relative h-full shrink-0 overflow-hidden rounded-xl bg-white shadow-sm", style: isPhone
|
|
121
|
+
? undefined
|
|
122
|
+
: { width: isFolderInline ? LAYOUT_WIDTHS.list : LAYOUT_WIDTHS.listCompact }, children: [_jsx(DeskConversationList, { onOpenAppMenu: onOpenAppMenu }), !isFolderInline && _jsx(FolderOverlay, {})] }), _jsxs("div", { ref: chatPaneRef, className: isPhone
|
|
123
|
+
? `absolute inset-0 flex flex-col overflow-hidden bg-white ${showThread ? "" : "invisible"}`
|
|
124
|
+
: "flex h-full flex-1 overflow-hidden rounded-xl bg-white shadow-sm", style: isPhone ? undefined : { minWidth: isDesktop ? LAYOUT_WIDTHS.chatMin : 0 }, children: [isPhone && !hasConversationData && (_jsx(PhoneThreadFallbackHeader, { onBack: backToList, onOpenAppMenu: onOpenAppMenu })), messageList] }), _jsx(ThreadInfo, { isOpen: isInfoOpen, onClose: closeInfo, groupConfig: groupThreadInfoConfig, supportPanelInline: isSupportPanelInline, drawerContainer: workspaceEl }), _jsx("div", { ref: setPanelSlotEl, className: "contents" }), _jsx(ShortcutHelpModal, { open: isHelpOpen, onClose: () => setIsHelpOpen(false) }), isOffline && (_jsx(DeskOfflineOverlay, { isPhone: isPhone, onOpenAppMenu: onOpenAppMenu, children: offlineContent }))] }));
|
|
56
125
|
};
|
|
57
126
|
export default DeskWorkspace;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Placeholder with DeskWorkspace's panels (folder, list, chat) so the desk keeps its shape while
|
|
4
|
+
* the chat engine boots. `children` sits centred in the chat panel. Also used by the CRM app shell.
|
|
5
|
+
*/
|
|
6
|
+
declare const DeskWorkspaceSkeleton: ({ children }: {
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export default DeskWorkspaceSkeleton;
|
|
10
|
+
//# sourceMappingURL=DeskWorkspaceSkeleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeskWorkspaceSkeleton.d.ts","sourceRoot":"","sources":["../../../src/screens/desk-message/DeskWorkspaceSkeleton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AASvC;;;GAGG;AACH,QAAA,MAAM,qBAAqB,GAAI,cAAc;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,4CA2CpE,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import DeskListSkeleton from "../../components/conversation/DeskListSkeleton";
|
|
4
|
+
import { LAYOUT_BREAKPOINTS, LAYOUT_WIDTHS } from "../../constants/layout";
|
|
5
|
+
import { useMediaQuery } from "../../hooks/common/useMediaQuery";
|
|
6
|
+
const minWidth = (px) => `(min-width: ${px}px)`;
|
|
7
|
+
const FOLDER_ROW_WIDTHS = ["w-3/4", "w-2/3", "w-4/5", "w-1/2", "w-3/5"];
|
|
8
|
+
const PULSE = "bg-gray-25 motion-safe:animate-pulse";
|
|
9
|
+
/**
|
|
10
|
+
* Placeholder with DeskWorkspace's panels (folder, list, chat) so the desk keeps its shape while
|
|
11
|
+
* the chat engine boots. `children` sits centred in the chat panel. Also used by the CRM app shell.
|
|
12
|
+
*/
|
|
13
|
+
const DeskWorkspaceSkeleton = ({ children }) => {
|
|
14
|
+
const isSupported = useMediaQuery(minWidth(LAYOUT_BREAKPOINTS.minWorkspace));
|
|
15
|
+
const isFolderInline = useMediaQuery(minWidth(LAYOUT_BREAKPOINTS.folderInline));
|
|
16
|
+
return (_jsxs("div", { "data-cp-name": "DeskWorkspaceSkeleton", className: "relative flex h-full min-h-0 flex-1 flex-row gap-2 overflow-hidden bg-gray-5 p-2", children: [isSupported && isFolderInline && (_jsxs("div", { "aria-hidden": "true", className: "flex h-full shrink-0 flex-col gap-4 rounded-xl bg-white p-4 shadow-sm", style: { width: LAYOUT_WIDTHS.folder }, children: [_jsx("span", { className: `h-4 w-24 rounded ${PULSE}` }), FOLDER_ROW_WIDTHS.map((width) => (_jsx("span", { className: `h-3 rounded ${width} ${PULSE}` }, width)))] })), isSupported && (_jsxs("div", { "aria-hidden": "true", className: "flex h-full shrink-0 flex-col overflow-hidden rounded-xl bg-white shadow-sm", style: { width: isFolderInline ? LAYOUT_WIDTHS.list : LAYOUT_WIDTHS.listCompact }, children: [_jsxs("div", { className: "flex items-center gap-2 p-3", children: [!isFolderInline && _jsx("span", { className: `h-9 w-9 shrink-0 rounded-lg ${PULSE}` }), _jsx("span", { className: `h-9 flex-1 rounded-lg ${PULSE}` }), _jsx("span", { className: `h-8 w-8 shrink-0 rounded-lg ${PULSE}` })] }), _jsx("div", { className: "border-b border-gray-25 px-4 pb-3 pt-1", children: _jsx("span", { className: `block h-3 w-28 rounded ${PULSE}` }) }), _jsx(DeskListSkeleton, { rows: 8 })] })), _jsx("div", { className: "flex h-full min-w-0 flex-1 items-center justify-center overflow-hidden rounded-xl bg-white p-6 shadow-sm", children: children })] }));
|
|
17
|
+
};
|
|
18
|
+
export default DeskWorkspaceSkeleton;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface PhoneThreadFallbackHeaderProps {
|
|
2
|
+
onBack: () => void;
|
|
3
|
+
onOpenAppMenu?: (opener: HTMLElement | null) => void;
|
|
4
|
+
}
|
|
5
|
+
/** Phone exit from a thread whose header can't render (still loading, removed or no access). */
|
|
6
|
+
declare const PhoneThreadFallbackHeader: ({ onBack, onOpenAppMenu, }: PhoneThreadFallbackHeaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default PhoneThreadFallbackHeader;
|
|
8
|
+
//# sourceMappingURL=PhoneThreadFallbackHeader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhoneThreadFallbackHeader.d.ts","sourceRoot":"","sources":["../../../src/screens/desk-message/PhoneThreadFallbackHeader.tsx"],"names":[],"mappings":"AAIA,UAAU,8BAA8B;IACtC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;CACtD;AAKD,gGAAgG;AAChG,QAAA,MAAM,yBAAyB,GAAI,4BAGhC,8BAA8B,4CA6BhC,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import { StrokeIcon } from "../../components/icon/StrokeIcon";
|
|
5
|
+
const buttonClass = "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg border-0 bg-transparent p-0 text-gray-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200";
|
|
6
|
+
/** Phone exit from a thread whose header can't render (still loading, removed or no access). */
|
|
7
|
+
const PhoneThreadFallbackHeader = ({ onBack, onOpenAppMenu, }) => {
|
|
8
|
+
const { t } = useTranslation();
|
|
9
|
+
return (_jsxs("div", { className: "flex h-14 shrink-0 items-center gap-1 border-b border-gray-25 bg-white px-2", "data-cp-name": "PhoneThreadFallbackHeader", children: [_jsx("button", { type: "button", "data-desk-back": true, "aria-label": t("back"), onClick: onBack, className: buttonClass, children: _jsx(StrokeIcon, { name: "chevron-left", size: 20 }) }), onOpenAppMenu && (_jsx("button", { type: "button", "data-app-menu-button": true, "aria-label": t("app_menu_open"), onClick: (event) => onOpenAppMenu(event.currentTarget), className: buttonClass, children: _jsx(StrokeIcon, { name: "menu", size: 20 }) }))] }));
|
|
10
|
+
};
|
|
11
|
+
export default PhoneThreadFallbackHeader;
|
|
@@ -6,6 +6,8 @@ interface DChatDeskMessageProps {
|
|
|
6
6
|
onCopyMessageLink?: (conversationId: string, clientMsgID: string) => void;
|
|
7
7
|
/** Called instead of the SDK's default toast when a jumped-to message turns out to be revoked. */
|
|
8
8
|
onSearchMessageRevoked?: () => void;
|
|
9
|
+
/** Phone: opens the host's app menu from the list header or thread fallback header; gets the tapped button. */
|
|
10
|
+
onOpenAppMenu?: (opener: HTMLElement | null) => void;
|
|
9
11
|
}
|
|
10
12
|
declare const DChatDeskMessage: (props: DChatDeskMessageProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
13
|
export default DChatDeskMessage;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/desk-message/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/desk-message/index.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAK5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAIxD,UAAU,qBAAqB;IAC7B,qBAAqB,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAChE,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IACpC,+GAA+G;IAC/G,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;CACtD;AAWD,QAAA,MAAM,gBAAgB,GAAI,OAAO,qBAAqB,4CA4CrD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -1,11 +1,55 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
3
5
|
import { useChatContext } from "../../context/ChatContext";
|
|
4
|
-
import { Spin } from "antd";
|
|
5
6
|
import { ConnectStatus } from "../../types/chat";
|
|
7
|
+
import { QUERY_KEYS } from "../../services/query";
|
|
8
|
+
import { useChatBootPhase } from "../../hooks/init/useChatBootPhase";
|
|
6
9
|
import DeskWorkspace from "./DeskWorkspace";
|
|
10
|
+
import DeskWorkspaceSkeleton from "./DeskWorkspaceSkeleton";
|
|
11
|
+
import DeskBootCard from "./DeskBootCard";
|
|
12
|
+
const DESK_SLOW_AFTER_MS = 15000;
|
|
13
|
+
// Lists behind the desk; they refetch after a reconnect because events were missed while offline.
|
|
14
|
+
const DESK_QUERY_KEYS = [
|
|
15
|
+
QUERY_KEYS.GET_TEAM_SESSIONS,
|
|
16
|
+
QUERY_KEYS.GET_SESSION_BY_TAG_OR_STATUS,
|
|
17
|
+
QUERY_KEYS.GET_SESSION_SUMMARY,
|
|
18
|
+
QUERY_KEYS.GET_TEAM_SESSION_SUMMARY,
|
|
19
|
+
QUERY_KEYS.GET_CONVERSATION_GROUPS,
|
|
20
|
+
];
|
|
7
21
|
const DChatDeskMessage = (props) => {
|
|
22
|
+
const boot = useChatBootPhase({ slowAfterMs: DESK_SLOW_AFTER_MS });
|
|
8
23
|
const { connectStatus } = useChatContext();
|
|
9
|
-
|
|
24
|
+
const queryClient = useQueryClient();
|
|
25
|
+
const isConnected = connectStatus === ConnectStatus.Connected;
|
|
26
|
+
// After the first full boot the desk stays mounted, so a reconnect keeps scroll, search and panels.
|
|
27
|
+
const [hasBooted, setHasBooted] = useState(boot.phase === "ready");
|
|
28
|
+
const wasDropped = useRef(false);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (boot.phase === "ready")
|
|
31
|
+
setHasBooted(true);
|
|
32
|
+
}, [boot.phase]);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (!hasBooted)
|
|
35
|
+
return;
|
|
36
|
+
if (!isConnected) {
|
|
37
|
+
wasDropped.current = true;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!wasDropped.current)
|
|
41
|
+
return;
|
|
42
|
+
wasDropped.current = false;
|
|
43
|
+
queryClient.invalidateQueries({
|
|
44
|
+
predicate: ({ queryKey }) => {
|
|
45
|
+
const head = Array.isArray(queryKey) ? queryKey[0] : queryKey;
|
|
46
|
+
return typeof head === "string" && DESK_QUERY_KEYS.includes(head);
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
}, [hasBooted, isConnected, queryClient]);
|
|
50
|
+
if (!hasBooted && boot.phase !== "ready") {
|
|
51
|
+
return (_jsx(DeskWorkspaceSkeleton, { children: _jsx(DeskBootCard, { boot: boot }) }));
|
|
52
|
+
}
|
|
53
|
+
return (_jsx(DeskWorkspace, Object.assign({}, props, { isOffline: !isConnected, offlineContent: isConnected ? undefined : _jsx(DeskBootCard, { boot: boot }) })));
|
|
10
54
|
};
|
|
11
55
|
export default DChatDeskMessage;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Boot steps that can fail before the first sync. */
|
|
2
|
+
export type ChatBootFailedStep = "engine" | "connect";
|
|
3
|
+
interface BootStore {
|
|
4
|
+
/** User the current boot belongs to; logging in as someone else starts over. */
|
|
5
|
+
userID: string | null;
|
|
6
|
+
hasConnected: boolean;
|
|
7
|
+
/** Set by the first OnSyncServerFinish/Failed after login, or when we stop waiting on a stalled sync. */
|
|
8
|
+
isFirstSyncDone: boolean;
|
|
9
|
+
/** The first sync was released by the stall timer, not finished; a real finish clears it. */
|
|
10
|
+
isSyncStalled: boolean;
|
|
11
|
+
/** A conversation list load finished after the first sync, so an empty list really is empty. */
|
|
12
|
+
isListSettled: boolean;
|
|
13
|
+
failedStep: ChatBootFailedStep | null;
|
|
14
|
+
/** 0-100 from OnSyncServerProgress (only sent while a fresh device syncs). */
|
|
15
|
+
syncProgress: number;
|
|
16
|
+
startBoot: (userID: string) => void;
|
|
17
|
+
reset: () => void;
|
|
18
|
+
markConnecting: () => void;
|
|
19
|
+
markConnected: () => void;
|
|
20
|
+
markFailed: (step: ChatBootFailedStep) => void;
|
|
21
|
+
setSyncProgress: (progress: number) => void;
|
|
22
|
+
markFirstSyncDone: () => void;
|
|
23
|
+
markSyncStalled: () => void;
|
|
24
|
+
markListSettled: () => void;
|
|
25
|
+
}
|
|
26
|
+
/** Progress of the chat engine boot (WASM, login, connect, first sync) shared by the loading screens. */
|
|
27
|
+
declare const useBootStore: import("zustand").UseBoundStore<import("zustand").StoreApi<BootStore>>;
|
|
28
|
+
export default useBootStore;
|
|
29
|
+
//# sourceMappingURL=boot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../../src/store/boot.ts"],"names":[],"mappings":"AAEA,sDAAsD;AACtD,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEtD,UAAU,SAAS;IACjB,gFAAgF;IAChF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,yGAAyG;IACzG,eAAe,EAAE,OAAO,CAAC;IACzB,6FAA6F;IAC7F,aAAa,EAAE,OAAO,CAAC;IACvB,gGAAgG;IAChG,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACtC,8EAA8E;IAC9E,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,UAAU,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC/C,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,eAAe,EAAE,MAAM,IAAI,CAAC;CAC7B;AAYD,yGAAyG;AACzG,QAAA,MAAM,YAAY,wEAkBf,CAAC;AAEJ,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { create } from "zustand";
|
|
2
|
+
const initialState = {
|
|
3
|
+
userID: null,
|
|
4
|
+
hasConnected: false,
|
|
5
|
+
isFirstSyncDone: false,
|
|
6
|
+
isSyncStalled: false,
|
|
7
|
+
isListSettled: false,
|
|
8
|
+
failedStep: null,
|
|
9
|
+
syncProgress: 0,
|
|
10
|
+
};
|
|
11
|
+
/** Progress of the chat engine boot (WASM, login, connect, first sync) shared by the loading screens. */
|
|
12
|
+
const useBootStore = create((set, get) => (Object.assign(Object.assign({}, initialState), { startBoot: (userID) => {
|
|
13
|
+
if (get().userID === userID)
|
|
14
|
+
return;
|
|
15
|
+
set(Object.assign(Object.assign({}, initialState), { userID }));
|
|
16
|
+
}, reset: () => set(initialState), markConnecting: () => set({ failedStep: null }), markConnected: () => set({ hasConnected: true, failedStep: null }), markFailed: (step) => set({ failedStep: step }), setSyncProgress: (progress) => set({ syncProgress: Math.max(0, Math.min(100, Math.round(progress))) }), markFirstSyncDone: () => set({ isFirstSyncDone: true, isSyncStalled: false }), markSyncStalled: () => {
|
|
17
|
+
if (get().isFirstSyncDone)
|
|
18
|
+
return;
|
|
19
|
+
set({ isFirstSyncDone: true, isSyncStalled: true });
|
|
20
|
+
}, markListSettled: () => set({ isListSettled: true }) })));
|
|
21
|
+
export default useBootStore;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ConversationStore } from "./type";
|
|
2
2
|
export declare const setUrlStateEnabled: (enabled: boolean) => void;
|
|
3
|
+
/** URL params that point at a thread (or a message inside it); cleared together. */
|
|
4
|
+
export declare const THREAD_URL_PARAMS: readonly ["threadId", "conversationId", "groupId", "botId", "userId", "messageId"];
|
|
3
5
|
export declare const setUrlNavigate: (fn: ((url: string) => void) | null) => void;
|
|
4
6
|
declare const useConversationStore: import("zustand").UseBoundStore<import("zustand").StoreApi<ConversationStore>>;
|
|
5
7
|
export default useConversationStore;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/store/conversation.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAY3C,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,SAElD,CAAC;
|
|
1
|
+
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/store/conversation.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAY3C,eAAO,MAAM,kBAAkB,GAAI,SAAS,OAAO,SAElD,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,oFAOpB,CAAC;AAUX,eAAO,MAAM,cAAc,GAAI,IAAI,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,IAAI,SAEhE,CAAC;AAEF,QAAA,MAAM,oBAAoB,gFAmhBvB,CAAC;AAEJ,eAAe,oBAAoB,CAAC"}
|
|
@@ -14,6 +14,15 @@ let urlStateEnabled = true;
|
|
|
14
14
|
export const setUrlStateEnabled = (enabled) => {
|
|
15
15
|
urlStateEnabled = enabled;
|
|
16
16
|
};
|
|
17
|
+
/** URL params that point at a thread (or a message inside it); cleared together. */
|
|
18
|
+
export const THREAD_URL_PARAMS = [
|
|
19
|
+
"threadId",
|
|
20
|
+
"conversationId",
|
|
21
|
+
"groupId",
|
|
22
|
+
"botId",
|
|
23
|
+
"userId",
|
|
24
|
+
"messageId",
|
|
25
|
+
];
|
|
17
26
|
// Module-level (not store state): ChatProvider syncs this from its onNavigate
|
|
18
27
|
// prop, same reason as urlStateEnabled above. clearSelectedConversation uses
|
|
19
28
|
// this instead of window.history.replaceState directly — Next's Pages Router
|
|
@@ -297,11 +306,11 @@ const useConversationStore = create((set, get) => ({
|
|
|
297
306
|
return { currentMemberInGroup: next };
|
|
298
307
|
});
|
|
299
308
|
},
|
|
300
|
-
clearSelectedConversation: () => {
|
|
309
|
+
clearSelectedConversation: (options) => {
|
|
301
310
|
// DeskConversationList's threadId-driven effect re-selects the same
|
|
302
311
|
// conversation on its next run otherwise (conversationList changes
|
|
303
312
|
// trigger it) — clobbering this reset right back.
|
|
304
|
-
if (urlStateEnabled && typeof window !== "undefined") {
|
|
313
|
+
if (!(options === null || options === void 0 ? void 0 : options.skipUrl) && urlStateEnabled && typeof window !== "undefined") {
|
|
305
314
|
const params = new URLSearchParams(window.location.search);
|
|
306
315
|
// `conversationId` is an accepted alias for `threadId`; groupId/botId/
|
|
307
316
|
// userId are the BIZ inbox's notification/deep-link entry params —
|
|
@@ -317,17 +326,9 @@ const useConversationStore = create((set, get) => ({
|
|
|
317
326
|
// sweeping it separately) also means a messageId left over on its own
|
|
318
327
|
// still gets cleaned; that costs at most one extra navigate, which
|
|
319
328
|
// self-terminates because the next clear finds nothing stale.
|
|
320
|
-
const
|
|
321
|
-
"threadId",
|
|
322
|
-
"conversationId",
|
|
323
|
-
"groupId",
|
|
324
|
-
"botId",
|
|
325
|
-
"userId",
|
|
326
|
-
"messageId",
|
|
327
|
-
];
|
|
328
|
-
const hadStaleParam = staleParams.some((key) => params.has(key));
|
|
329
|
+
const hadStaleParam = THREAD_URL_PARAMS.some((key) => params.has(key));
|
|
329
330
|
if (hadStaleParam) {
|
|
330
|
-
|
|
331
|
+
THREAD_URL_PARAMS.forEach((key) => params.delete(key));
|
|
331
332
|
const query = params.toString();
|
|
332
333
|
const url = `${window.location.pathname}${query ? `?${query}` : ""}`;
|
|
333
334
|
// Prefer the host's router (set via setUrlNavigate) so Next's
|