@droppii-org/chat-sdk 0.7.6 → 0.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/conversation/ThreadCard.d.ts +2 -1
- package/dist/components/conversation/ThreadCard.d.ts.map +1 -1
- package/dist/components/conversation/ThreadCard.js +2 -2
- package/dist/components/conversation-detail/ConversationDetailHeader.d.ts +5 -1
- package/dist/components/conversation-detail/ConversationDetailHeader.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationDetailHeader.js +3 -3
- package/dist/components/conversation-detail/ConversationMoreOptionPanel.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationMoreOptionPanel.js +3 -1
- package/dist/components/conversation-detail/ThreadProfilePanel.d.ts +5 -1
- package/dist/components/conversation-detail/ThreadProfilePanel.d.ts.map +1 -1
- package/dist/components/conversation-detail/ThreadProfilePanel.js +13 -3
- package/dist/components/conversation-detail/profile/PinThreadLimitModal.d.ts +7 -0
- package/dist/components/conversation-detail/profile/PinThreadLimitModal.d.ts.map +1 -0
- package/dist/components/conversation-detail/profile/PinThreadLimitModal.js +14 -0
- package/dist/components/conversation-detail/profile/ThreadProfileActionRows.d.ts +15 -0
- package/dist/components/conversation-detail/profile/ThreadProfileActionRows.d.ts.map +1 -0
- package/dist/components/conversation-detail/profile/ThreadProfileActionRows.js +20 -0
- package/dist/components/conversation-detail/profile/ThreadProfileQuickActions.d.ts +11 -0
- package/dist/components/conversation-detail/profile/ThreadProfileQuickActions.d.ts.map +1 -0
- package/dist/components/conversation-detail/profile/ThreadProfileQuickActions.js +36 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchContent.d.ts +13 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchContent.d.ts.map +1 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchContent.js +70 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchPanel.d.ts +11 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchPanel.d.ts.map +1 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchPanel.js +12 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchResultItem.d.ts +11 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchResultItem.d.ts.map +1 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchResultItem.js +24 -0
- package/dist/components/conversation-detail/thread-search/utils.d.ts +8 -0
- package/dist/components/conversation-detail/thread-search/utils.d.ts.map +1 -0
- package/dist/components/conversation-detail/thread-search/utils.js +17 -0
- package/dist/components/conversation-inbox/ConversationInboxItem.d.ts +3 -1
- package/dist/components/conversation-inbox/ConversationInboxItem.d.ts.map +1 -1
- package/dist/components/conversation-inbox/ConversationInboxItem.js +4 -6
- package/dist/components/conversation-inbox/ConversationInboxList.d.ts +3 -1
- package/dist/components/conversation-inbox/ConversationInboxList.d.ts.map +1 -1
- package/dist/components/conversation-inbox/ConversationInboxList.js +2 -2
- package/dist/components/conversation-inbox/ConversationThreadActions.d.ts +12 -0
- package/dist/components/conversation-inbox/ConversationThreadActions.d.ts.map +1 -0
- package/dist/components/conversation-inbox/ConversationThreadActions.js +58 -0
- package/dist/components/conversation-inbox/contact-search/ContactSearchCommunitySection.d.ts +10 -0
- package/dist/components/conversation-inbox/contact-search/ContactSearchCommunitySection.d.ts.map +1 -0
- package/dist/components/conversation-inbox/contact-search/ContactSearchCommunitySection.js +15 -0
- package/dist/components/conversation-inbox/contact-search/ContactSearchPanel.d.ts.map +1 -1
- package/dist/components/conversation-inbox/contact-search/ContactSearchPanel.js +39 -28
- package/dist/components/conversation-inbox/contact-search/constants.js +2 -2
- package/dist/components/conversation-inbox/index.d.ts +2 -2
- package/dist/components/conversation-inbox/index.d.ts.map +1 -1
- package/dist/components/conversation-inbox/index.js +1 -1
- package/dist/components/group/MemberPermissionPanel.d.ts.map +1 -1
- package/dist/components/group/MemberPermissionPanel.js +12 -23
- package/dist/components/message/toolbox/MessageToolboxMenu.d.ts +7 -0
- package/dist/components/message/toolbox/MessageToolboxMenu.d.ts.map +1 -1
- package/dist/components/message/toolbox/MessageToolboxMenu.js +1 -1
- package/dist/constants/moreOption.d.ts +1 -0
- package/dist/constants/moreOption.d.ts.map +1 -1
- package/dist/hooks/conversation/useBotFlow.d.ts.map +1 -1
- package/dist/hooks/conversation/useBotFlow.js +42 -23
- package/dist/hooks/conversation/useConversationTarget.d.ts +4 -0
- package/dist/hooks/conversation/useConversationTarget.d.ts.map +1 -0
- package/dist/hooks/conversation/useConversationTarget.js +23 -0
- package/dist/hooks/conversation/usePinConversation.d.ts +10 -0
- package/dist/hooks/conversation/usePinConversation.d.ts.map +1 -0
- package/dist/hooks/conversation/usePinConversation.js +52 -0
- package/dist/hooks/message/holdMessageHighlight.d.ts +6 -0
- package/dist/hooks/message/holdMessageHighlight.d.ts.map +1 -0
- package/dist/hooks/message/holdMessageHighlight.js +22 -0
- package/dist/hooks/message/useMessageListScroll.d.ts.map +1 -1
- package/dist/hooks/message/useMessageListScroll.js +13 -0
- package/dist/hooks/message/useSendMessage.d.ts +1 -1
- package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
- package/dist/hooks/message/useSendMessage.js +358 -285
- package/dist/hooks/search/useSearchPublicGroups.d.ts +1 -0
- package/dist/hooks/search/useSearchPublicGroups.d.ts.map +1 -1
- package/dist/hooks/search/useSearchPublicGroups.js +6 -0
- package/dist/hooks/search/useSearchThreadMessages.d.ts +222 -0
- package/dist/hooks/search/useSearchThreadMessages.d.ts.map +1 -0
- package/dist/hooks/search/useSearchThreadMessages.js +60 -0
- package/dist/locales/vi/conversation-inbox.json +31 -0
- package/dist/screens/conversation-detail/index.d.ts +5 -1
- package/dist/screens/conversation-detail/index.d.ts.map +1 -1
- package/dist/screens/conversation-detail/index.js +17 -2
- package/dist/screens/conversation-inbox/index.d.ts +6 -0
- package/dist/screens/conversation-inbox/index.d.ts.map +1 -1
- package/dist/screens/conversation-inbox/index.js +3 -3
- package/dist/services/query.d.ts +3 -0
- package/dist/services/query.d.ts.map +1 -1
- package/dist/services/query.js +3 -0
- package/dist/services/routes.d.ts +2 -0
- package/dist/services/routes.d.ts.map +1 -1
- package/dist/services/routes.js +2 -0
- package/dist/store/conversation.d.ts.map +1 -1
- package/dist/store/conversation.js +10 -6
- package/dist/store/type.d.ts +3 -0
- package/dist/store/type.d.ts.map +1 -1
- package/dist/styles/global.css +1 -1
- package/dist/types/conversation.d.ts +8 -0
- package/dist/types/conversation.d.ts.map +1 -1
- package/dist/utils/common.d.ts +7 -0
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/common.js +42 -13
- package/dist/utils/sendQueue.d.ts +2 -0
- package/dist/utils/sendQueue.d.ts.map +1 -0
- package/dist/utils/sendQueue.js +14 -0
- package/package.json +1 -1
- package/dist/components/conversation-inbox/ConversationMuteSwipeAction.d.ts +0 -8
- package/dist/components/conversation-inbox/ConversationMuteSwipeAction.d.ts.map +0 -1
- package/dist/components/conversation-inbox/ConversationMuteSwipeAction.js +0 -31
|
@@ -13,7 +13,7 @@ import InboxBootStatus from "./InboxBootStatus";
|
|
|
13
13
|
import InboxListSkeleton from "./InboxListSkeleton";
|
|
14
14
|
const INBOX_SLOW_AFTER_MS = 8000;
|
|
15
15
|
const FooterSkeleton = () => (_jsxs("div", { className: "flex items-center gap-3 p-3", children: [_jsx("div", { className: "h-10 w-10 animate-pulse rounded-full bg-neutral-200" }), _jsxs("div", { className: "flex flex-1 flex-col gap-2", children: [_jsx("div", { className: "h-3 w-1/2 animate-pulse rounded bg-neutral-200" }), _jsx("div", { className: "h-2.5 w-1/3 animate-pulse rounded bg-neutral-200" })] })] }));
|
|
16
|
-
const ConversationInboxList = ({ items, isLoading, isFetchingNextPage, hasNextPage, onLoadMore, onSelectThread, }) => {
|
|
16
|
+
const ConversationInboxList = ({ items, isLoading, isFetchingNextPage, hasNextPage, onLoadMore, onSelectThread, showPinThread = false, }) => {
|
|
17
17
|
const { t } = useTranslation("conversation-inbox");
|
|
18
18
|
const onNavigate = useChatNavigate();
|
|
19
19
|
const boot = useChatBootPhase({ slowAfterMs: INBOX_SLOW_AFTER_MS });
|
|
@@ -41,6 +41,6 @@ const ConversationInboxList = ({ items, isLoading, isFetchingNextPage, hasNextPa
|
|
|
41
41
|
return (_jsxs("div", { "data-testid": "conversation-inbox-thread-list", className: "min-h-0 w-full flex-1 overflow-hidden", children: [!isListSettled && (_jsx(InboxBootStatus, { boot: boot.phase === "ready"
|
|
42
42
|
? Object.assign(Object.assign({}, boot), { phase: "sync", syncProgress: 100 }) : boot })), boot.phase !== "error" && _jsx(InboxListSkeleton, { rows: 6 })] }));
|
|
43
43
|
}
|
|
44
|
-
return (_jsx("div", { id: "scrollableConversationThreadsDiv", "data-testid": "conversation-inbox-thread-list", "data-cp-name": "ConversationInboxList", className: "min-h-0 w-full flex-1 overflow-auto", children: _jsx(InfiniteScroll, { dataLength: items.length, next: handleEndReached, hasMore: hasNextPage, loader: isFetchingNextPage ? _jsx(FooterSkeleton, {}) : null, scrollableTarget: "scrollableConversationThreadsDiv", children: items.length === 0 ? (_jsx("div", { className: "flex items-center justify-center py-12", children: _jsx(Empty, { image: _jsx("div", { className: "flex justify-center", children: _jsx(Icon, { icon: "chat-square-b", size: 80, className: "text-[var(--dc-color-primary-light)]" }) }), description: t("empty.no_conversations") }) })) : (items.map((item) => (_jsx(ConversationInboxItem, { item: item, onClick: handleSelectThread }, item.conversationID)))) }) }));
|
|
44
|
+
return (_jsx("div", { id: "scrollableConversationThreadsDiv", "data-testid": "conversation-inbox-thread-list", "data-cp-name": "ConversationInboxList", className: "min-h-0 w-full flex-1 overflow-auto", children: _jsx(InfiniteScroll, { dataLength: items.length, next: handleEndReached, hasMore: hasNextPage, loader: isFetchingNextPage ? _jsx(FooterSkeleton, {}) : null, scrollableTarget: "scrollableConversationThreadsDiv", children: items.length === 0 ? (_jsx("div", { className: "flex items-center justify-center py-12", children: _jsx(Empty, { image: _jsx("div", { className: "flex justify-center", children: _jsx(Icon, { icon: "chat-square-b", size: 80, className: "text-[var(--dc-color-primary-light)]" }) }), description: t("empty.no_conversations") }) })) : (items.map((item) => (_jsx(ConversationInboxItem, { item: item, onClick: handleSelectThread, showPinThread: showPinThread }, item.conversationID)))) }) }));
|
|
45
45
|
};
|
|
46
46
|
export default ConversationInboxList;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { ConversationItem } from "@droppii-org/wasm-client-sdk";
|
|
3
|
+
export interface ConversationThreadActionsProps {
|
|
4
|
+
conversation: ConversationItem;
|
|
5
|
+
isMuted: boolean;
|
|
6
|
+
/** Adds Ghim / Bỏ ghim to the swipe actions and a right-click menu on the card. */
|
|
7
|
+
showPin: boolean;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
declare const ConversationThreadActions: ({ conversation, isMuted, showPin, children, }: ConversationThreadActionsProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export default ConversationThreadActions;
|
|
12
|
+
//# sourceMappingURL=ConversationThreadActions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConversationThreadActions.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/ConversationThreadActions.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAcrE,MAAM,WAAW,8BAA8B;IAC7C,YAAY,EAAE,gBAAgB,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,mFAAmF;IACnF,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,QAAA,MAAM,yBAAyB,GAAI,+CAKhC,8BAA8B,4CAkHhC,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Dropdown } from "antd";
|
|
5
|
+
import { useTranslation } from "react-i18next";
|
|
6
|
+
import SwipeableRow from "../../components/conversation/SwipeableRow";
|
|
7
|
+
import SwipeActionButton, { SWIPE_ACTION_WIDTH, } from "../../components/conversation/SwipeActionButton";
|
|
8
|
+
import { MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, ToolboxMenuRow, } from "../../components/message/toolbox";
|
|
9
|
+
import PinThreadLimitModal from "../../components/conversation-detail/profile/PinThreadLimitModal";
|
|
10
|
+
import { useMuteConversation } from "../../hooks/session/useMuteConversation";
|
|
11
|
+
import { usePinConversation } from "../../hooks/conversation/usePinConversation";
|
|
12
|
+
import MuteConversationConfirmModal from "./MuteConversationConfirmModal";
|
|
13
|
+
const ConversationThreadActions = ({ conversation, isMuted, showPin, children, }) => {
|
|
14
|
+
const { t } = useTranslation("conversation-inbox");
|
|
15
|
+
const { muteConversation, unmuteConversation, isPending: isMutePending, } = useMuteConversation();
|
|
16
|
+
const { togglePin, isLimitOpen, closeLimit } = usePinConversation();
|
|
17
|
+
const [isMuteConfirmOpen, setIsMuteConfirmOpen] = useState(false);
|
|
18
|
+
const { conversationID } = conversation;
|
|
19
|
+
const isPinned = !!conversation.isPinned;
|
|
20
|
+
const muteLabel = t(isMuted ? "thread_card.mute.unmute_action" : "thread_card.mute.mute_action");
|
|
21
|
+
const pinLabel = t(isPinned ? "thread_card.pin.unpin_action" : "thread_card.pin.pin_action");
|
|
22
|
+
// Muting asks first; unmuting doesn't.
|
|
23
|
+
const handleToggleMute = () => {
|
|
24
|
+
if (isMuted) {
|
|
25
|
+
void unmuteConversation(conversationID);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
setIsMuteConfirmOpen(true);
|
|
29
|
+
};
|
|
30
|
+
const handleConfirmMute = () => {
|
|
31
|
+
setIsMuteConfirmOpen(false);
|
|
32
|
+
void muteConversation(conversationID);
|
|
33
|
+
};
|
|
34
|
+
const handleTogglePin = () => {
|
|
35
|
+
void togglePin(conversation);
|
|
36
|
+
};
|
|
37
|
+
const swipeRow = (_jsx(SwipeableRow, { actionsWidth: SWIPE_ACTION_WIDTH * (showPin ? 2 : 1), actions: (closeSwipe) => (_jsxs(_Fragment, { children: [_jsx(SwipeActionButton, { testId: "conversation-inbox-mute-action", icon: isMuted ? "bell-b" : "bell-off-b", label: muteLabel, onClick: () => {
|
|
38
|
+
closeSwipe();
|
|
39
|
+
handleToggleMute();
|
|
40
|
+
}, className: "bg-gray-400" }), showPin && (_jsx(SwipeActionButton, { testId: "conversation-inbox-pin-action", icon: isPinned ? "thumbtack-off-b" : "thumbtack-b", label: pinLabel, onClick: () => {
|
|
41
|
+
closeSwipe();
|
|
42
|
+
handleTogglePin();
|
|
43
|
+
}, className: "bg-[var(--dc-color-primary)]" }))] })), children: children }));
|
|
44
|
+
const menuItems = [
|
|
45
|
+
{
|
|
46
|
+
key: "mute",
|
|
47
|
+
label: (_jsx(ToolboxMenuRow, { icon: isMuted ? "bell-o" : "bell-off-o", label: muteLabel })),
|
|
48
|
+
onClick: handleToggleMute,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
key: "pin",
|
|
52
|
+
label: (_jsx(ToolboxMenuRow, { icon: isPinned ? "thumbtack-off-o" : "thumbtack-o", label: pinLabel })),
|
|
53
|
+
onClick: handleTogglePin,
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
return (_jsxs(_Fragment, { children: [showPin ? (_jsx(Dropdown, { menu: { items: menuItems }, trigger: ["contextMenu"], overlayClassName: MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, children: _jsx("div", { "data-testid": "conversation-inbox-thread-actions", children: swipeRow }) })) : (swipeRow), _jsx(MuteConversationConfirmModal, { open: isMuteConfirmOpen, loading: isMutePending, onCancel: () => setIsMuteConfirmOpen(false), onConfirm: handleConfirmMute }), showPin && _jsx(PinThreadLimitModal, { open: isLimitOpen, onClose: closeLimit })] }));
|
|
57
|
+
};
|
|
58
|
+
export default ConversationThreadActions;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SearchPublicGroupInfo } from "@droppii-org/wasm-client-sdk";
|
|
2
|
+
interface ContactSearchCommunitySectionProps {
|
|
3
|
+
groups: SearchPublicGroupInfo[];
|
|
4
|
+
total: number;
|
|
5
|
+
onOpenGroup: (groupID: string) => void;
|
|
6
|
+
onViewAll: () => void;
|
|
7
|
+
}
|
|
8
|
+
declare const ContactSearchCommunitySection: ({ groups, total, onOpenGroup, onViewAll, }: ContactSearchCommunitySectionProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export default ContactSearchCommunitySection;
|
|
10
|
+
//# sourceMappingURL=ContactSearchCommunitySection.d.ts.map
|
package/dist/components/conversation-inbox/contact-search/ContactSearchCommunitySection.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContactSearchCommunitySection.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/ContactSearchCommunitySection.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAM1E,UAAU,kCAAkC;IAC1C,MAAM,EAAE,qBAAqB,EAAE,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAGD,QAAA,MAAM,6BAA6B,GAAI,4CAKpC,kCAAkC,4CAwBpC,CAAC;AAEF,eAAe,6BAA6B,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import ContactSearchSectionHeader from "./ContactSearchSectionHeader";
|
|
5
|
+
import ContactSearchViewMoreBar from "./ContactSearchViewMoreBar";
|
|
6
|
+
import PublicGroupResultItem from "./PublicGroupResultItem";
|
|
7
|
+
import { CONTACT_SEARCH_PREVIEW_LIMIT } from "./constants";
|
|
8
|
+
// `Tất cả` preview of the `Cộng đồng` tab: same cards, capped like contacts.
|
|
9
|
+
const ContactSearchCommunitySection = ({ groups, total, onOpenGroup, onViewAll, }) => {
|
|
10
|
+
const { t } = useTranslation("conversation-inbox");
|
|
11
|
+
// Guards a short server total so a full page still gets its hand-off.
|
|
12
|
+
const matchCount = Math.max(total, groups.length);
|
|
13
|
+
return (_jsxs("section", { "data-cp-name": "ContactSearchCommunitySection", children: [_jsx(ContactSearchSectionHeader, { title: t("contact_search.tabs.community"), count: matchCount || undefined, onSelect: onViewAll }), groups.slice(0, CONTACT_SEARCH_PREVIEW_LIMIT).map((group) => (_jsx(PublicGroupResultItem, { group: group, onOpen: onOpenGroup }, group.groupID))), matchCount > CONTACT_SEARCH_PREVIEW_LIMIT && (_jsx(ContactSearchViewMoreBar, { onSelect: onViewAll }))] }));
|
|
14
|
+
};
|
|
15
|
+
export default ContactSearchCommunitySection;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContactSearchPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/ContactSearchPanel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ContactSearchPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/ContactSearchPanel.tsx"],"names":[],"mappings":"AAgCA,UAAU,uBAAuB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,kBAAkB,GAAI,mBAAmB,uBAAuB,4CA2TrE,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -10,6 +10,7 @@ import { useChatNavigate } from "../../../hooks/conversation/useChatNavigate";
|
|
|
10
10
|
import { useSearchContacts } from "../../../hooks/search/useSearchContacts";
|
|
11
11
|
import { useSearchPublicGroups } from "../../../hooks/search/useSearchPublicGroups";
|
|
12
12
|
import useConversationStore from "../../../store/conversation";
|
|
13
|
+
import ContactSearchCommunitySection from "./ContactSearchCommunitySection";
|
|
13
14
|
import ContactSearchFilters from "./ContactSearchFilters";
|
|
14
15
|
import ContactSearchResultItem from "./ContactSearchResultItem";
|
|
15
16
|
import ContactSearchSectionHeader from "./ContactSearchSectionHeader";
|
|
@@ -46,9 +47,12 @@ const ContactSearchPanel = ({ open, onClose }) => {
|
|
|
46
47
|
type: activeType,
|
|
47
48
|
enabled: open,
|
|
48
49
|
});
|
|
50
|
+
// `Tất cả` and `Cộng đồng` share one query, so switching tabs hits the cache.
|
|
49
51
|
const publicGroups = useSearchPublicGroups({
|
|
50
52
|
searchTerm: trimmedKeyword,
|
|
51
|
-
enabled: open &&
|
|
53
|
+
enabled: open &&
|
|
54
|
+
(activeTab === ContactSearchTab.All ||
|
|
55
|
+
activeTab === ContactSearchTab.Community),
|
|
52
56
|
});
|
|
53
57
|
const handleOpenGroup = (groupID) => {
|
|
54
58
|
const target = { groupId: groupID };
|
|
@@ -72,46 +76,53 @@ const ContactSearchPanel = ({ open, onClose }) => {
|
|
|
72
76
|
setActiveType(undefined);
|
|
73
77
|
};
|
|
74
78
|
const renderContactItems = (items) => items.map((contact) => (_jsx(ContactSearchResultItem, { contact: contact, searchTerm: trimmedKeyword, onSelect: handleSelectContact }, contact.id)));
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
const renderInitialState = (testId = "contact-search-initial") => (_jsx(ContactSearchStateMessage, { testId: testId, children: t("contact_search.initial") }));
|
|
80
|
+
const renderLoadingState = () => (_jsx("div", { className: "flex flex-1 items-center justify-center py-12", children: _jsx(Spin, {}) }));
|
|
81
|
+
const renderFailedState = (testId = "contact-search-failed") => (_jsx(ContactSearchStateMessage, { testId: testId, children: t("contact_search.failed") }));
|
|
82
|
+
const renderNoResultState = (testId = "contact-search-no-result") => (_jsxs(ContactSearchStateMessage, { testId: testId, children: [t("contact_search.no_result_title"), _jsx("br", {}), t("contact_search.no_result_hint")] }));
|
|
83
|
+
// The `Liên hệ` tab's not-ready states before it can render results;
|
|
84
|
+
// returns null once there is a list to show.
|
|
77
85
|
const renderPlaceholderState = () => {
|
|
78
|
-
if (!trimmedKeyword)
|
|
79
|
-
return (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (
|
|
85
|
-
return (
|
|
86
|
-
}
|
|
87
|
-
if (contacts.length === 0) {
|
|
88
|
-
return (_jsxs(ContactSearchStateMessage, { testId: "contact-search-no-result", children: [t("contact_search.no_result_title"), _jsx("br", {}), t("contact_search.no_result_hint")] }));
|
|
89
|
-
}
|
|
86
|
+
if (!trimmedKeyword)
|
|
87
|
+
return renderInitialState();
|
|
88
|
+
if (isLoading)
|
|
89
|
+
return renderLoadingState();
|
|
90
|
+
if (isError)
|
|
91
|
+
return renderFailedState();
|
|
92
|
+
if (contacts.length === 0)
|
|
93
|
+
return renderNoResultState();
|
|
90
94
|
return null;
|
|
91
95
|
};
|
|
92
|
-
// `Tất cả`
|
|
93
|
-
//
|
|
96
|
+
// `Tất cả` previews contacts, then public groups; the message section
|
|
97
|
+
// belongs to the message-search ticket and goes between the two.
|
|
94
98
|
const renderAllTab = () => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
if (!trimmedKeyword)
|
|
100
|
+
return renderInitialState();
|
|
101
|
+
if (isLoading || publicGroups.isLoading)
|
|
102
|
+
return renderLoadingState();
|
|
103
|
+
if (isError && publicGroups.isError)
|
|
104
|
+
return renderFailedState();
|
|
105
|
+
// A source that failed drops its own section instead of the whole tab.
|
|
106
|
+
const showContacts = !isError && contacts.length > 0;
|
|
107
|
+
const showGroups = !publicGroups.isError && publicGroups.groups.length > 0;
|
|
108
|
+
if (!showContacts && !showGroups)
|
|
109
|
+
return renderNoResultState();
|
|
110
|
+
const hasMoreContacts = contacts.length > CONTACT_SEARCH_PREVIEW_LIMIT || !!hasNextPage;
|
|
99
111
|
const openContactsTab = () => handleChangeTab(ContactSearchTab.Contacts);
|
|
100
|
-
return (_jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsx(ContactSearchSectionHeader, { title: t("contact_search.tabs.contacts"), count: totalElements || undefined, onSelect: openContactsTab }), renderContactItems(contacts.slice(0, CONTACT_SEARCH_PREVIEW_LIMIT)),
|
|
112
|
+
return (_jsxs("div", { className: "flex-1 overflow-y-auto", children: [showContacts && (_jsxs("section", { children: [_jsx(ContactSearchSectionHeader, { title: t("contact_search.tabs.contacts"), count: totalElements || undefined, onSelect: openContactsTab }), renderContactItems(contacts.slice(0, CONTACT_SEARCH_PREVIEW_LIMIT)), hasMoreContacts && (_jsx(ContactSearchViewMoreBar, { onSelect: openContactsTab }))] })), showGroups && (_jsx(ContactSearchCommunitySection, { groups: publicGroups.groups, total: publicGroups.total, onOpenGroup: handleOpenGroup, onViewAll: () => handleChangeTab(ContactSearchTab.Community) }))] }));
|
|
101
113
|
};
|
|
102
114
|
const renderContactList = () => (_jsx("div", { id: SCROLL_TARGET_ID, className: "flex-1 overflow-y-auto", children: _jsx(InfiniteScroll, { dataLength: contacts.length, next: fetchNextPage, hasMore: !!hasNextPage, scrollableTarget: SCROLL_TARGET_ID, loader: isFetchingNextPage ? (_jsx("div", { className: "flex items-center justify-center py-3", children: _jsx(Spin, { size: "small" }) })) : null, children: renderContactItems(contacts) }) }));
|
|
103
115
|
const renderCommunityTab = () => {
|
|
104
116
|
if (!trimmedKeyword) {
|
|
105
|
-
return (
|
|
106
|
-
}
|
|
107
|
-
if (publicGroups.isLoading) {
|
|
108
|
-
return (_jsx("div", { className: "flex flex-1 items-center justify-center py-12", children: _jsx(Spin, {}) }));
|
|
117
|
+
return renderInitialState("contact-search-community-initial");
|
|
109
118
|
}
|
|
119
|
+
if (publicGroups.isLoading)
|
|
120
|
+
return renderLoadingState();
|
|
110
121
|
if (publicGroups.isError) {
|
|
111
|
-
return (
|
|
122
|
+
return renderFailedState("contact-search-community-failed");
|
|
112
123
|
}
|
|
113
124
|
if (publicGroups.groups.length === 0) {
|
|
114
|
-
return (
|
|
125
|
+
return renderNoResultState("contact-search-community-no-result");
|
|
115
126
|
}
|
|
116
127
|
return (_jsx("div", { id: COMMUNITY_SCROLL_TARGET_ID, className: "flex-1 overflow-y-auto", children: _jsx(InfiniteScroll, { dataLength: publicGroups.groups.length, next: publicGroups.fetchNextPage, hasMore: !!publicGroups.hasNextPage, scrollableTarget: COMMUNITY_SCROLL_TARGET_ID, loader: publicGroups.isFetchingNextPage ? (_jsx("div", { className: "flex items-center justify-center py-3", children: _jsx(Spin, { size: "small" }) })) : null, children: publicGroups.groups.map((group) => (_jsx(PublicGroupResultItem, { group: group, onOpen: handleOpenGroup }, group.groupID))) }) }));
|
|
117
128
|
};
|
|
@@ -2,8 +2,8 @@ import { ContactSearchType } from "../../../types/dto";
|
|
|
2
2
|
export const CONTACT_SEARCH_DEBOUNCE_MS = 300;
|
|
3
3
|
export const CONTACT_SEARCH_ICON_SIZE = 18;
|
|
4
4
|
export const CONTACT_SEARCH_AVATAR_SIZE = 48;
|
|
5
|
-
// `Tất cả`
|
|
6
|
-
// seller over to the full `Liên hệ` tab.
|
|
5
|
+
// `Tất cả` caps each section's preview (contacts, public groups) before handing
|
|
6
|
+
// the seller over to the full `Liên hệ` / `Cộng đồng` tab.
|
|
7
7
|
export const CONTACT_SEARCH_PREVIEW_LIMIT = 5;
|
|
8
8
|
export var ContactSearchTab;
|
|
9
9
|
(function (ContactSearchTab) {
|
|
@@ -7,8 +7,8 @@ export { default as ConversationInboxItem } from "./ConversationInboxItem";
|
|
|
7
7
|
export type { ConversationInboxItemProps } from "./ConversationInboxItem";
|
|
8
8
|
export { default as ConversationInboxList } from "./ConversationInboxList";
|
|
9
9
|
export type { ConversationInboxListProps } from "./ConversationInboxList";
|
|
10
|
-
export { default as
|
|
11
|
-
export type {
|
|
10
|
+
export { default as ConversationThreadActions } from "./ConversationThreadActions";
|
|
11
|
+
export type { ConversationThreadActionsProps } from "./ConversationThreadActions";
|
|
12
12
|
export { default as MuteConversationConfirmModal } from "./MuteConversationConfirmModal";
|
|
13
13
|
export type { MuteConversationConfirmModalProps } from "./MuteConversationConfirmModal";
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAE/E,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAC7E,YAAY,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAE5E,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAC7E,YAAY,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAE5E,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,YAAY,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAE1E,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,YAAY,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAE1E,OAAO,EAAE,OAAO,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAE/E,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAC7E,YAAY,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAE5E,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAC7E,YAAY,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAE5E,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,YAAY,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAE1E,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,YAAY,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAE1E,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnF,YAAY,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAC;AAElF,OAAO,EAAE,OAAO,IAAI,4BAA4B,EAAE,MAAM,gCAAgC,CAAC;AACzF,YAAY,EAAE,iCAAiC,EAAE,MAAM,gCAAgC,CAAC"}
|
|
@@ -3,5 +3,5 @@ export { default as ConversationPeerAvatar } from "./ConversationPeerAvatar";
|
|
|
3
3
|
export { default as ConversationInboxTitle } from "./ConversationInboxTitle";
|
|
4
4
|
export { default as ConversationInboxItem } from "./ConversationInboxItem";
|
|
5
5
|
export { default as ConversationInboxList } from "./ConversationInboxList";
|
|
6
|
-
export { default as
|
|
6
|
+
export { default as ConversationThreadActions } from "./ConversationThreadActions";
|
|
7
7
|
export { default as MuteConversationConfirmModal } from "./MuteConversationConfirmModal";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemberPermissionPanel.d.ts","sourceRoot":"","sources":["../../../src/components/group/MemberPermissionPanel.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MemberPermissionPanel.d.ts","sourceRoot":"","sources":["../../../src/components/group/MemberPermissionPanel.tsx"],"names":[],"mappings":"AAoBA,UAAU,0BAA0B;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AA6BD,QAAA,MAAM,qBAAqB,GAAI,4BAA4B,0BAA0B,mDAgHpF,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx,
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { ConfigProvider, Switch, message } from "antd";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
@@ -9,24 +9,22 @@ import { useSetMemberRolePermissions } from "../../hooks/group/useGroupMemberAct
|
|
|
9
9
|
import { Icon } from "../../components/icon";
|
|
10
10
|
import useAuthStore from "../../store/auth";
|
|
11
11
|
import PermissionPanelCrm from "./PermissionPanelCrm";
|
|
12
|
-
import DisableSendPermissionConfirm from "./DisableSendPermissionConfirm";
|
|
13
12
|
import { ANTD_PRIMARY_COLOR_VAR } from "../../constants";
|
|
14
13
|
import { GROUP_PERMISSION_KEY } from "../../constants/im";
|
|
15
14
|
import { changedSwitches, commonSwitchStates, toRolePermissionChange, } from "../../utils/groupPermissionSwitches";
|
|
15
|
+
// No "Gửi tin nhắn" switch: members are muted from the group send toggle or one by one,
|
|
16
|
+
// and saving here never touches SEND_MESSAGE.
|
|
16
17
|
const SWITCH_PERMISSION_KEYS = {
|
|
17
|
-
sendMessage: [GROUP_PERMISSION_KEY.sendMessage],
|
|
18
18
|
addMember: [GROUP_PERMISSION_KEY.addMember],
|
|
19
19
|
pinMessage: [GROUP_PERMISSION_KEY.pinMessage],
|
|
20
20
|
viewMemberInformation: [GROUP_PERMISSION_KEY.viewMemberInformation],
|
|
21
21
|
};
|
|
22
22
|
const SWITCH_LABELS = {
|
|
23
|
-
sendMessage: "permission_send_message",
|
|
24
23
|
addMember: "permission_add_member",
|
|
25
24
|
pinMessage: "permission_pin_message",
|
|
26
25
|
viewMemberInformation: "permission_view_member_info",
|
|
27
26
|
};
|
|
28
27
|
const SWITCH_DESCRIPTIONS = {
|
|
29
|
-
sendMessage: "permission_desc_send_message",
|
|
30
28
|
addMember: "permission_desc_add_member",
|
|
31
29
|
pinMessage: "permission_desc_pin_message",
|
|
32
30
|
viewMemberInformation: "permission_desc_view_member_info",
|
|
@@ -41,7 +39,6 @@ const MemberPermissionPanel = ({ open, groupID, onClose }) => {
|
|
|
41
39
|
const { mutateAsync: setMemberRolePermissions } = useSetMemberRolePermissions();
|
|
42
40
|
const isCrm = useAuthStore((state) => state.isCrm);
|
|
43
41
|
const [isSaving, setIsSaving] = useState(false);
|
|
44
|
-
const [isConfirmOpen, setIsConfirmOpen] = useState(false);
|
|
45
42
|
const [edits, setEdits] = useState({});
|
|
46
43
|
useEffect(() => {
|
|
47
44
|
if (open)
|
|
@@ -52,17 +49,9 @@ const MemberPermissionPanel = ({ open, groupID, onClose }) => {
|
|
|
52
49
|
const pending = Object.assign(Object.assign({}, baseline), edits);
|
|
53
50
|
const changes = changedSwitches(baseline, pending);
|
|
54
51
|
const hasChanges = Object.keys(changes).length > 0;
|
|
55
|
-
const requestSave = () => {
|
|
56
|
-
if (isCrm && changes.sendMessage === false) {
|
|
57
|
-
setIsConfirmOpen(true);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
void handleSave();
|
|
61
|
-
};
|
|
62
52
|
const handleSave = async () => {
|
|
63
53
|
if (!groupID || !hasChanges)
|
|
64
54
|
return;
|
|
65
|
-
setIsConfirmOpen(false);
|
|
66
55
|
setIsSaving(true);
|
|
67
56
|
try {
|
|
68
57
|
await setMemberRolePermissions(Object.assign({ groupID }, toRolePermissionChange(SWITCH_PERMISSION_KEYS, changes)));
|
|
@@ -80,15 +69,15 @@ const MemberPermissionPanel = ({ open, groupID, onClose }) => {
|
|
|
80
69
|
if (!open)
|
|
81
70
|
return null;
|
|
82
71
|
if (isCrm) {
|
|
83
|
-
return (
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
72
|
+
return (_jsx(PermissionPanelCrm, { title: t("member_permission_row"), rows: SWITCHES.map((name) => ({
|
|
73
|
+
key: name,
|
|
74
|
+
label: t(SWITCH_LABELS[name]),
|
|
75
|
+
description: t(SWITCH_DESCRIPTIONS[name]),
|
|
76
|
+
checked: pending[name],
|
|
77
|
+
disabled: isLoading,
|
|
78
|
+
onChange: (checked) => setEdits((prev) => (Object.assign(Object.assign({}, prev), { [name]: checked }))),
|
|
79
|
+
})), canSave: hasChanges && !isLoading, isSaving: isSaving, onBack: onClose, onSave: handleSave }));
|
|
91
80
|
}
|
|
92
|
-
return (_jsxs("div", { className: "absolute inset-0 bg-white flex flex-col z-10", "data-cp-name": "MemberPermissionPanel", children: [_jsxs("div", { className: "flex w-full items-center border-b border-gray-100 p-2", children: [_jsx("button", { type: "button", className: "flex shrink-0 cursor-pointer items-center justify-center p-2 text-[var(--dc-color-nav-icon)]", onClick: onClose, children: _jsx(Icon, { icon: "arrow-left-o", size: 24 }) }), _jsx("p", { className: "min-w-0 flex-1 truncate px-2 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("member_permission_settings") })] }), _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx(ConfigProvider, { theme: { token: { colorPrimary: ANTD_PRIMARY_COLOR_VAR } }, children: _jsx("div", { className: "flex flex-col py-2", children: SWITCHES.map((name) => (_jsxs("div", { className: "flex items-center justify-between px-4 py-3", children: [_jsx("span", { className: "text-sm", children: t(SWITCH_LABELS[name]) }), _jsx(Switch, { checked: pending[name], disabled: isLoading, onChange: (checked) => setEdits((prev) => (Object.assign(Object.assign({}, prev), { [name]: checked }))) })] }, name))) }) }) }), _jsxs("div", { className: "flex items-center justify-end gap-2 px-4 py-3 border-t border-gray-100", children: [_jsx("button", { type: "button", className: "px-4 py-1.5 rounded-full border border-gray-300 text-gray-700 text-sm font-medium", onClick: onClose, children: t("cancel") }), _jsx("button", { type: "button", className: "px-4 py-1.5 rounded-full bg-[var(--dc-color-primary)] text-white text-sm font-medium disabled:bg-gray-200 disabled:text-gray-400", disabled: !hasChanges || isSaving || isLoading, onClick:
|
|
81
|
+
return (_jsxs("div", { className: "absolute inset-0 bg-white flex flex-col z-10", "data-cp-name": "MemberPermissionPanel", children: [_jsxs("div", { className: "flex w-full items-center border-b border-gray-100 p-2", children: [_jsx("button", { type: "button", className: "flex shrink-0 cursor-pointer items-center justify-center p-2 text-[var(--dc-color-nav-icon)]", onClick: onClose, children: _jsx(Icon, { icon: "arrow-left-o", size: 24 }) }), _jsx("p", { className: "min-w-0 flex-1 truncate px-2 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("member_permission_settings") })] }), _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx(ConfigProvider, { theme: { token: { colorPrimary: ANTD_PRIMARY_COLOR_VAR } }, children: _jsx("div", { className: "flex flex-col py-2", children: SWITCHES.map((name) => (_jsxs("div", { className: "flex items-center justify-between px-4 py-3", children: [_jsx("span", { className: "text-sm", children: t(SWITCH_LABELS[name]) }), _jsx(Switch, { checked: pending[name], disabled: isLoading, onChange: (checked) => setEdits((prev) => (Object.assign(Object.assign({}, prev), { [name]: checked }))) })] }, name))) }) }) }), _jsxs("div", { className: "flex items-center justify-end gap-2 px-4 py-3 border-t border-gray-100", children: [_jsx("button", { type: "button", className: "px-4 py-1.5 rounded-full border border-gray-300 text-gray-700 text-sm font-medium", onClick: onClose, children: t("cancel") }), _jsx("button", { type: "button", className: "px-4 py-1.5 rounded-full bg-[var(--dc-color-primary)] text-white text-sm font-medium disabled:bg-gray-200 disabled:text-gray-400", disabled: !hasChanges || isSaving || isLoading, onClick: handleSave, children: t("save") })] })] }));
|
|
93
82
|
};
|
|
94
83
|
export default MemberPermissionPanel;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { MenuProps } from "antd";
|
|
2
2
|
import { MessageToolboxAction } from "./types";
|
|
3
3
|
export declare const MESSAGE_TOOLBOX_OVERLAY_CLASSNAME: string;
|
|
4
|
+
interface ToolboxMenuRowProps {
|
|
5
|
+
icon: string;
|
|
6
|
+
label: string;
|
|
7
|
+
danger?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const ToolboxMenuRow: ({ icon, label, danger }: ToolboxMenuRowProps) => import("react/jsx-runtime").JSX.Element;
|
|
4
10
|
export declare const buildMessageToolboxMenuItems: (actions: MessageToolboxAction[]) => NonNullable<MenuProps["items"]>;
|
|
11
|
+
export {};
|
|
5
12
|
//# sourceMappingURL=MessageToolboxMenu.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageToolboxMenu.d.ts","sourceRoot":"","sources":["../../../../src/components/message/toolbox/MessageToolboxMenu.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAKtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C,eAAO,MAAM,iCAAiC,QAS7C,CAAC;
|
|
1
|
+
{"version":3,"file":"MessageToolboxMenu.d.ts","sourceRoot":"","sources":["../../../../src/components/message/toolbox/MessageToolboxMenu.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAKtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C,eAAO,MAAM,iCAAiC,QAS7C,CAAC;AAEF,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAYD,eAAO,MAAM,cAAc,GAAI,yBAAiC,mBAAmB,4CA4BlF,CAAC;AAEF,eAAO,MAAM,4BAA4B,GACvC,SAAS,oBAAoB,EAAE,KAC9B,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAO5B,CAAC"}
|
|
@@ -13,7 +13,7 @@ const CRM_ICONS = {
|
|
|
13
13
|
"link-o": "link",
|
|
14
14
|
"trash-o": "undo",
|
|
15
15
|
};
|
|
16
|
-
const ToolboxMenuRow = ({ icon, label, danger = false }) => {
|
|
16
|
+
export const ToolboxMenuRow = ({ icon, label, danger = false }) => {
|
|
17
17
|
const isCrm = useAuthStore((state) => state.isCrm);
|
|
18
18
|
const crmIcon = isCrm ? CRM_ICONS[icon] : undefined;
|
|
19
19
|
return (_jsxs("div", { "data-cp-name": "ToolboxMenuRow", className: "flex items-center gap-3", children: [crmIcon ? (_jsx(StrokeIcon, { name: crmIcon, size: 18, className: danger ? "text-danger-600" : "text-gray-600" })) : (_jsx(Icon, { icon: icon, size: 24, className: danger ? "text-danger-400" : "text-gray-900" })), _jsx("span", { className: clsx("text-base font-medium", danger ? "text-danger-400" : "text-gray-900"), children: label })] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"moreOption.d.ts","sourceRoot":"","sources":["../../src/constants/moreOption.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;;;;CAOhB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC;AAE/E,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,eAAO,MAAM,oBAAoB,EAAE,gBAAgB,EAmBlD,CAAC;AAEF,wBAAgB,iBAAiB,CAC/B,YAAY,GAAE,gBAAgB,EAAO,GACpC,gBAAgB,EAAE,CAEpB;AAED,eAAO,MAAM,YAAY,EAAE,gBAAgB,EAmBzC,CAAC"}
|
|
1
|
+
{"version":3,"file":"moreOption.d.ts","sourceRoot":"","sources":["../../src/constants/moreOption.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa;;;;;;;CAOhB,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC;AAE/E,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,eAAO,MAAM,oBAAoB,EAAE,gBAAgB,EAmBlD,CAAC;AAEF,wBAAgB,iBAAiB,CAC/B,YAAY,GAAE,gBAAgB,EAAO,GACpC,gBAAgB,EAAE,CAEpB;AAED,eAAO,MAAM,YAAY,EAAE,gBAAgB,EAmBzC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBotFlow.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useBotFlow.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;AAgB9B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC;AAMtD,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;CACtB;AAsBD,eAAO,MAAM,UAAU,GAAI,kCAGxB,gBAAgB;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"useBotFlow.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useBotFlow.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACrB,MAAM,sBAAsB,CAAC;AAgB9B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,aAAa,CAAC;AAMtD,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;CACtB;AAsBD,eAAO,MAAM,UAAU,GAAI,kCAGxB,gBAAgB;;;;;;;;;;;;6BAoKqB,MAAM;;6BA+DN,eAAe;;;CAmDtD,CAAC"}
|
|
@@ -104,9 +104,22 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
|
|
|
104
104
|
buttons: inputButtonsBlocks.flatMap((block) => block.data.buttons),
|
|
105
105
|
} }) : null;
|
|
106
106
|
const isInActiveCsSession = isInCsSession({ flowCurrentStep: activeStep });
|
|
107
|
-
|
|
107
|
+
// Also true while a chosen label waits in the send queue behind earlier uploads,
|
|
108
|
+
// so a second click cannot run the same step twice.
|
|
109
|
+
const [isChoosing, setIsChoosing] = useState(false);
|
|
110
|
+
const isProcessing = isChoosing ||
|
|
111
|
+
runMutation.isPending ||
|
|
108
112
|
resetMutation.isPending ||
|
|
109
113
|
closeSessionMutation.isPending;
|
|
114
|
+
const whileChoosing = async (action) => {
|
|
115
|
+
setIsChoosing(true);
|
|
116
|
+
try {
|
|
117
|
+
await action();
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
setIsChoosing(false);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
110
123
|
const shouldShowButtons = !!currentButtonsBlock && !isProcessing && !pendingGroupId;
|
|
111
124
|
const status = (activeStep === null || activeStep === void 0 ? void 0 : activeStep.type) === BotFlowNodeType.Start ? "not_started" : "running";
|
|
112
125
|
const runStep = async (step, actionId = null) => {
|
|
@@ -144,15 +157,17 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
|
|
|
144
157
|
actionId,
|
|
145
158
|
};
|
|
146
159
|
const selectedButton = currentButtonsBlock === null || currentButtonsBlock === void 0 ? void 0 : currentButtonsBlock.data.buttons.find((button) => button.id === actionId);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
160
|
+
await whileChoosing(async () => {
|
|
161
|
+
if (selectedButton) {
|
|
162
|
+
await sendMergeMessage({
|
|
163
|
+
plainText: selectedButton.label,
|
|
164
|
+
richText: "",
|
|
165
|
+
isInternal: false,
|
|
166
|
+
flow,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
await runStep(activeStep, actionId);
|
|
170
|
+
});
|
|
156
171
|
};
|
|
157
172
|
const performRestart = async () => {
|
|
158
173
|
var _a;
|
|
@@ -161,14 +176,16 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
|
|
|
161
176
|
childId: null,
|
|
162
177
|
actionId: BOT_DEFAULT_BUTTON_ID,
|
|
163
178
|
};
|
|
164
|
-
await
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
179
|
+
await whileChoosing(async () => {
|
|
180
|
+
await sendMergeMessage({
|
|
181
|
+
plainText: t("thread_detail.bot.restart"),
|
|
182
|
+
richText: "",
|
|
183
|
+
isInternal: false,
|
|
184
|
+
flow,
|
|
185
|
+
});
|
|
186
|
+
const resetDetail = await resetMutation.mutateAsync(conversationId);
|
|
187
|
+
await runStep(resetDetail.flowCurrentStep);
|
|
169
188
|
});
|
|
170
|
-
const resetDetail = await resetMutation.mutateAsync(conversationId);
|
|
171
|
-
await runStep(resetDetail.flowCurrentStep);
|
|
172
189
|
};
|
|
173
190
|
const restart = async () => {
|
|
174
191
|
if (isInActiveCsSession) {
|
|
@@ -180,13 +197,15 @@ export const useBotFlow = ({ conversationId, isBotThread, }) => {
|
|
|
180
197
|
const runMenuOption = async (item) => {
|
|
181
198
|
if (!activeStep)
|
|
182
199
|
return;
|
|
183
|
-
await
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
200
|
+
await whileChoosing(async () => {
|
|
201
|
+
await sendMergeMessage({
|
|
202
|
+
plainText: item.label,
|
|
203
|
+
richText: "",
|
|
204
|
+
isInternal: false,
|
|
205
|
+
flow: { groupId: activeStep.id, childId: null, actionId: item.id },
|
|
206
|
+
});
|
|
207
|
+
await runStep(activeStep, item.id);
|
|
188
208
|
});
|
|
189
|
-
await runStep(activeStep, item.id);
|
|
190
209
|
};
|
|
191
210
|
const selectMenuOption = async (item) => {
|
|
192
211
|
if (item.id === BOT_DEFAULT_BUTTON_ID) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useConversationTarget.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/useConversationTarget.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,qBAAqB,GAChC,gBAAgB,MAAM,EACtB,SAAS,OAAO;;CAkBjB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useQuery } from "@tanstack/react-query";
|
|
3
|
+
import { apiInstance } from "../../services/api";
|
|
4
|
+
import { ENDPOINTS } from "../../services/routes";
|
|
5
|
+
import { QUERY_KEYS } from "../../services/query";
|
|
6
|
+
// Whether the peer account is still active. Fails open like biz-mobile:
|
|
7
|
+
// a pending or failed lookup counts as active.
|
|
8
|
+
export const useConversationTarget = (conversationId, enabled) => {
|
|
9
|
+
var _a;
|
|
10
|
+
const query = useQuery({
|
|
11
|
+
queryKey: [QUERY_KEYS.GET_CONVERSATION_TARGET, conversationId],
|
|
12
|
+
queryFn: async () => {
|
|
13
|
+
const res = await apiInstance.get(ENDPOINTS.chatService.getConversationTarget(conversationId));
|
|
14
|
+
return res.data.data;
|
|
15
|
+
},
|
|
16
|
+
enabled: enabled && !!conversationId,
|
|
17
|
+
staleTime: 0,
|
|
18
|
+
retry: false,
|
|
19
|
+
refetchOnWindowFocus: false,
|
|
20
|
+
});
|
|
21
|
+
// isError first: a failed refetch keeps the previous data in react-query.
|
|
22
|
+
return { isTargetActive: query.isError || ((_a = query.data) === null || _a === void 0 ? void 0 : _a.isActive) !== false };
|
|
23
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ConversationItem } from "@droppii-org/wasm-client-sdk";
|
|
2
|
+
/** Thread pin cap, checked client-side like biz-mobile. */
|
|
3
|
+
export declare const MAX_PINNED_THREADS = 5;
|
|
4
|
+
export declare const usePinConversation: () => {
|
|
5
|
+
togglePin: (conversation: ConversationItem) => Promise<void>;
|
|
6
|
+
isPending: boolean;
|
|
7
|
+
isLimitOpen: boolean;
|
|
8
|
+
closeLimit: () => void;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=usePinConversation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePinConversation.d.ts","sourceRoot":"","sources":["../../../src/hooks/conversation/usePinConversation.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAKrE,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAMpC,eAAO,MAAM,kBAAkB;8BAUU,gBAAgB;;;;CAkCxD,CAAC"}
|