@droppii-org/chat-sdk 0.4.8 → 0.4.10
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/DeskConversationList.d.ts.map +1 -1
- package/dist/components/conversation/DeskConversationList.js +8 -2
- package/dist/components/conversation-detail/ConversationDetailInput.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationDetailInput.js +10 -5
- package/dist/components/conversation-inbox/contact-search/ContactSearchPanel.d.ts.map +1 -1
- package/dist/components/conversation-inbox/contact-search/ContactSearchPanel.js +36 -0
- package/dist/components/conversation-inbox/contact-search/ContactSearchResultItem.d.ts.map +1 -1
- package/dist/components/conversation-inbox/contact-search/ContactSearchResultItem.js +4 -2
- package/dist/components/conversation-inbox/contact-search/PublicGroupAvatar.d.ts +9 -0
- package/dist/components/conversation-inbox/contact-search/PublicGroupAvatar.d.ts.map +1 -0
- package/dist/components/conversation-inbox/contact-search/PublicGroupAvatar.js +19 -0
- package/dist/components/conversation-inbox/contact-search/PublicGroupResultItem.d.ts +8 -0
- package/dist/components/conversation-inbox/contact-search/PublicGroupResultItem.d.ts.map +1 -0
- package/dist/components/conversation-inbox/contact-search/PublicGroupResultItem.js +29 -0
- package/dist/components/conversation-inbox/contact-search/constants.d.ts +4 -1
- package/dist/components/conversation-inbox/contact-search/constants.d.ts.map +1 -1
- package/dist/components/conversation-inbox/contact-search/constants.js +5 -0
- package/dist/components/conversation-inbox/contact-search/index.d.ts +2 -0
- package/dist/components/conversation-inbox/contact-search/index.d.ts.map +1 -1
- package/dist/components/conversation-inbox/contact-search/index.js +2 -0
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +3 -1
- package/dist/components/message/footer/index.d.ts.map +1 -1
- package/dist/components/message/footer/index.js +2 -2
- package/dist/components/message/footer/mention/MentionMenu.d.ts +1 -0
- package/dist/components/message/footer/mention/MentionMenu.d.ts.map +1 -1
- package/dist/components/message/footer/mention/MentionMenu.js +66 -6
- package/dist/components/message/footer/mention/MentionNode.d.ts +1 -1
- package/dist/components/message/footer/mention/MentionNode.d.ts.map +1 -1
- package/dist/components/message/footer/mention/MentionNode.js +2 -2
- package/dist/components/message/footer/mention/useMentionOptions.d.ts.map +1 -1
- package/dist/components/message/footer/mention/useMentionOptions.js +6 -3
- package/dist/components/search-conversation/index.d.ts.map +1 -1
- package/dist/components/search-conversation/index.js +20 -2
- package/dist/components/search-conversation/item/SearchItemAsGroup.d.ts.map +1 -1
- package/dist/components/search-conversation/item/SearchItemAsGroup.js +2 -1
- package/dist/components/search-conversation/item/SearchItemAsMessage.d.ts.map +1 -1
- package/dist/components/search-conversation/item/SearchItemAsMessage.js +4 -1
- package/dist/hooks/conversation/useResolveConversation.d.ts.map +1 -1
- package/dist/hooks/conversation/useResolveConversation.js +2 -1
- package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
- package/dist/hooks/global/useGlobalEvent.js +10 -1
- package/dist/hooks/group/useJoinPublicGroup.d.ts +6 -0
- package/dist/hooks/group/useJoinPublicGroup.d.ts.map +1 -0
- package/dist/hooks/group/useJoinPublicGroup.js +20 -0
- package/dist/hooks/search/useSearchMessage.d.ts.map +1 -1
- package/dist/hooks/search/useSearchMessage.js +11 -1
- package/dist/hooks/search/useSearchPublicGroups.d.ts +16 -0
- package/dist/hooks/search/useSearchPublicGroups.d.ts.map +1 -0
- package/dist/hooks/search/useSearchPublicGroups.js +55 -0
- package/dist/locales/vi/common.json +1 -1
- package/dist/locales/vi/conversation-inbox.json +7 -2
- package/dist/services/query.d.ts +1 -0
- package/dist/services/query.d.ts.map +1 -1
- package/dist/services/query.js +1 -0
- package/dist/store/conversation.d.ts.map +1 -1
- package/dist/store/conversation.js +22 -9
- package/dist/store/type.d.ts +6 -2
- package/dist/store/type.d.ts.map +1 -1
- package/dist/styles/global.css +1 -1
- package/dist/types/dto.d.ts +1 -0
- package/dist/types/dto.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AA4BA,QAAA,MAAM,oBAAoB,+
|
|
1
|
+
{"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AA4BA,QAAA,MAAM,oBAAoB,+CA2UzB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -90,8 +90,12 @@ const DeskConversationList = () => {
|
|
|
90
90
|
}
|
|
91
91
|
setSelectedConversationId(threadId);
|
|
92
92
|
const selectedConversation = conversationList.find((conv) => conv.conversationID === threadId);
|
|
93
|
+
// threadId can come from a notification/stale search click — force a
|
|
94
|
+
// fresh membership check instead of trusting the groupID cache.
|
|
93
95
|
if (selectedConversation) {
|
|
94
|
-
setConversationData(selectedConversation
|
|
96
|
+
setConversationData(selectedConversation, undefined, {
|
|
97
|
+
forceRevalidate: true,
|
|
98
|
+
});
|
|
95
99
|
}
|
|
96
100
|
else {
|
|
97
101
|
DChatSDK.getMultipleConversation([threadId]).then((res) => {
|
|
@@ -99,7 +103,9 @@ const DeskConversationList = () => {
|
|
|
99
103
|
// (e.g. the user was removed from that group mid-flight) — only
|
|
100
104
|
// apply the result if the URL still points at this conversation.
|
|
101
105
|
if (res.data.length > 0 && searchParams.get("threadId") === threadId) {
|
|
102
|
-
setConversationData(res.data[0]
|
|
106
|
+
setConversationData(res.data[0], undefined, {
|
|
107
|
+
forceRevalidate: true,
|
|
108
|
+
});
|
|
103
109
|
updateConversationList(res.data, "filter");
|
|
104
110
|
}
|
|
105
111
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAkB/D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,QAAA,MAAM,uBAAuB,GAAI,4EAM9B,4BAA4B,
|
|
1
|
+
{"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAkB/D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,QAAA,MAAM,uBAAuB,GAAI,4EAM9B,4BAA4B,4CAynB9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -19,7 +19,7 @@ import { ReplyPreviewBar } from "../../components/message/reply/ReplyPreviewBar"
|
|
|
19
19
|
import ConversationMoreOptionPanel from "./ConversationMoreOptionPanel";
|
|
20
20
|
import { useMentionTrigger } from "./mention/useMentionTrigger";
|
|
21
21
|
import { useMentionOptions } from "../../components/message/footer/mention/useMentionOptions";
|
|
22
|
-
import {
|
|
22
|
+
import { useMentionTokens } from "./mention/useMentionTokens";
|
|
23
23
|
import BizMentionMenu from "./mention/BizMentionMenu";
|
|
24
24
|
import { getCaretCoordinates, disposeCaretCoordinates, } from "./mention/getCaretCoordinates";
|
|
25
25
|
import { buildMentionPayload } from "./mention/buildMentionPayload";
|
|
@@ -69,11 +69,16 @@ const ConversationDetailInput = ({ placeholder, onSendMessage, onInputChange, mo
|
|
|
69
69
|
const { tokens: mentionTokens, addToken, onValueChange, resetTokens } = useMentionTokens();
|
|
70
70
|
// "Tất cả" doesn't count against the per-user cap and stays selectable;
|
|
71
71
|
// only specific-member options are hidden once the limit is hit.
|
|
72
|
-
const
|
|
72
|
+
const mentionedUserIDs = useMemo(() => new Set(mentionTokens.filter((token) => !token.isAtAll).map((token) => token.userID)), [mentionTokens]);
|
|
73
|
+
const mentionedUsersCount = mentionedUserIDs.size;
|
|
73
74
|
const mentionLimitReached = mentionedUsersCount >= MAX_MENTIONED_USERS;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
// Already-tagged users don't need to appear again in the same draft.
|
|
76
|
+
const mentionOptions = useMemo(() => {
|
|
77
|
+
const notYetMentioned = rawMentionOptions.filter((option) => option.isAtAll || !mentionedUserIDs.has(option.userID));
|
|
78
|
+
return mentionLimitReached
|
|
79
|
+
? notYetMentioned.filter((option) => option.isAtAll)
|
|
80
|
+
: notYetMentioned;
|
|
81
|
+
}, [rawMentionOptions, mentionedUserIDs, mentionLimitReached]);
|
|
77
82
|
const [mentionMenuPosition, setMentionMenuPosition] = useState(null);
|
|
78
83
|
const previewUrl = useMemo(() => {
|
|
79
84
|
const urls = extractLinkUrls(value);
|
|
@@ -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":"AA8BA,UAAU,uBAAuB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,kBAAkB,GAAI,mBAAmB,uBAAuB,4CAuTrE,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -8,15 +8,18 @@ import { useTranslation } from "react-i18next";
|
|
|
8
8
|
import { Icon } from "../../../components/icon";
|
|
9
9
|
import { useChatContext } from "../../../context/ChatContext";
|
|
10
10
|
import { useSearchContacts } from "../../../hooks/search/useSearchContacts";
|
|
11
|
+
import { useSearchPublicGroups } from "../../../hooks/search/useSearchPublicGroups";
|
|
11
12
|
import ContactSearchFilters from "./ContactSearchFilters";
|
|
12
13
|
import ContactSearchResultItem from "./ContactSearchResultItem";
|
|
13
14
|
import ContactSearchSectionHeader from "./ContactSearchSectionHeader";
|
|
14
15
|
import ContactSearchStateMessage from "./ContactSearchStateMessage";
|
|
15
16
|
import ContactSearchTabs from "./ContactSearchTabs";
|
|
16
17
|
import ContactSearchViewMoreBar from "./ContactSearchViewMoreBar";
|
|
18
|
+
import PublicGroupResultItem from "./PublicGroupResultItem";
|
|
17
19
|
import { CONTACT_SEARCH_DEBOUNCE_MS, CONTACT_SEARCH_ICON_SIZE, CONTACT_SEARCH_PREVIEW_LIMIT, ContactSearchTab, } from "./constants";
|
|
18
20
|
import { buildContactSearchParams } from "./utils";
|
|
19
21
|
const SCROLL_TARGET_ID = "contact-search-scroll";
|
|
22
|
+
const COMMUNITY_SCROLL_TARGET_ID = "contact-search-community-scroll";
|
|
20
23
|
const ContactSearchPanel = ({ open, onClose }) => {
|
|
21
24
|
const { t } = useTranslation("conversation-inbox");
|
|
22
25
|
const { onNavigate } = useChatContext();
|
|
@@ -41,6 +44,19 @@ const ContactSearchPanel = ({ open, onClose }) => {
|
|
|
41
44
|
type: activeType,
|
|
42
45
|
enabled: open,
|
|
43
46
|
});
|
|
47
|
+
const publicGroups = useSearchPublicGroups({
|
|
48
|
+
searchTerm: trimmedKeyword,
|
|
49
|
+
enabled: open && activeTab === ContactSearchTab.Community,
|
|
50
|
+
});
|
|
51
|
+
const handleOpenGroup = (groupID) => {
|
|
52
|
+
const params = new URLSearchParams(window.location.search);
|
|
53
|
+
params.delete("threadId");
|
|
54
|
+
params.delete("userId");
|
|
55
|
+
params.delete("botId");
|
|
56
|
+
params.set("groupId", groupID);
|
|
57
|
+
onClose();
|
|
58
|
+
onNavigate === null || onNavigate === void 0 ? void 0 : onNavigate(`${window.location.pathname}?${params.toString()}`);
|
|
59
|
+
};
|
|
44
60
|
const handleSelectContact = (contact) => {
|
|
45
61
|
const params = buildContactSearchParams(contact);
|
|
46
62
|
onClose();
|
|
@@ -82,6 +98,21 @@ const ContactSearchPanel = ({ open, onClose }) => {
|
|
|
82
98
|
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)), hasMore && _jsx(ContactSearchViewMoreBar, { onSelect: openContactsTab })] }));
|
|
83
99
|
};
|
|
84
100
|
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) }) }));
|
|
101
|
+
const renderCommunityTab = () => {
|
|
102
|
+
if (!trimmedKeyword) {
|
|
103
|
+
return (_jsx(ContactSearchStateMessage, { testId: "contact-search-community-initial", children: t("contact_search.initial") }));
|
|
104
|
+
}
|
|
105
|
+
if (publicGroups.isLoading) {
|
|
106
|
+
return (_jsx("div", { className: "flex flex-1 items-center justify-center py-12", children: _jsx(Spin, {}) }));
|
|
107
|
+
}
|
|
108
|
+
if (publicGroups.isError) {
|
|
109
|
+
return (_jsx(ContactSearchStateMessage, { testId: "contact-search-community-failed", children: t("contact_search.failed") }));
|
|
110
|
+
}
|
|
111
|
+
if (publicGroups.groups.length === 0) {
|
|
112
|
+
return (_jsxs(ContactSearchStateMessage, { testId: "contact-search-community-no-result", children: [t("contact_search.no_result_title"), _jsx("br", {}), t("contact_search.no_result_hint")] }));
|
|
113
|
+
}
|
|
114
|
+
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))) }) }));
|
|
115
|
+
};
|
|
85
116
|
// Filters stay mounted even with no results so the seller can switch type.
|
|
86
117
|
const renderContactsTab = () => {
|
|
87
118
|
var _a;
|
|
@@ -103,6 +134,11 @@ const ContactSearchPanel = ({ open, onClose }) => {
|
|
|
103
134
|
label: t("contact_search.tabs.messages"),
|
|
104
135
|
children: (_jsx(ContactSearchStateMessage, { testId: "contact-search-messages", children: t("contact_search.messages_not_available") })),
|
|
105
136
|
},
|
|
137
|
+
{
|
|
138
|
+
key: ContactSearchTab.Community,
|
|
139
|
+
label: t("contact_search.tabs.community"),
|
|
140
|
+
children: renderCommunityTab(),
|
|
141
|
+
},
|
|
106
142
|
];
|
|
107
143
|
return (_jsx(Drawer, { open: open, onClose: onClose, placement: "right", closeIcon: false, width: "100%", "data-cp-name": "ContactSearchPanel", styles: { body: { padding: 0 } }, getContainer: false, destroyOnHidden: true, children: _jsxs("div", { className: "flex h-full flex-col bg-white", children: [_jsxs("div", { className: "flex items-center gap-2 px-3 py-2", children: [_jsx("button", { type: "button", "data-testid": "contact-search-back", "aria-label": t("contact_search.back"), className: "flex shrink-0 cursor-pointer items-center justify-center p-1 text-primary-400", onClick: onClose, children: _jsx(Icon, { icon: "arrow-left-o", size: 24 }) }), _jsx(Input, { allowClear: true, autoFocus: true, value: keyword, "data-testid": "contact-search-input", placeholder: t("search_placeholder"), prefix: _jsx("span", { className: "flex h-10 w-10 items-center justify-center", children: _jsx(Icon, { icon: "search-o", size: CONTACT_SEARCH_ICON_SIZE }) }),
|
|
108
144
|
// Padding lives on the prefix/input instead of the wrapper so the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContactSearchResultItem.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/ContactSearchResultItem.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,iBAAiB,EAAqB,MAAM,aAAa,CAAC;AAGnE,UAAU,4BAA4B;IACpC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAChD;AAED,QAAA,MAAM,uBAAuB,GAAI,oCAI9B,4BAA4B,
|
|
1
|
+
{"version":3,"file":"ContactSearchResultItem.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/ContactSearchResultItem.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,iBAAiB,EAAqB,MAAM,aAAa,CAAC;AAGnE,UAAU,4BAA4B;IACpC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,CAAC,OAAO,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAChD;AAED,QAAA,MAAM,uBAAuB,GAAI,oCAI9B,4BAA4B,4CAqE9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -14,11 +14,13 @@ const ContactSearchResultItem = ({ contact, searchTerm, onSelect, }) => {
|
|
|
14
14
|
// Supporting line differs per contact type (spec §Contact Result Content).
|
|
15
15
|
// PDP intentionally has none — its last online time was dropped from spec.
|
|
16
16
|
const buildSupportingText = () => {
|
|
17
|
-
var _a;
|
|
17
|
+
var _a, _b;
|
|
18
18
|
if (isGroup) {
|
|
19
|
-
|
|
19
|
+
const memberCount = t("contact_search.member_count", {
|
|
20
20
|
count: (_a = contact.memberCount) !== null && _a !== void 0 ? _a : 0,
|
|
21
21
|
});
|
|
22
|
+
const description = ((_b = contact.description) === null || _b === void 0 ? void 0 : _b.trim()) || t("contact_search.group_no_description");
|
|
23
|
+
return `${memberCount} • ${description}`;
|
|
22
24
|
}
|
|
23
25
|
if (contact.type === ContactSearchType.PdpBot)
|
|
24
26
|
return "";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SearchPublicGroupMemberInfo } from "@droppii-org/wasm-client-sdk";
|
|
2
|
+
interface PublicGroupAvatarProps {
|
|
3
|
+
faceURL?: string;
|
|
4
|
+
groupName?: string;
|
|
5
|
+
members?: SearchPublicGroupMemberInfo[];
|
|
6
|
+
}
|
|
7
|
+
declare const PublicGroupAvatar: ({ faceURL, groupName, members, }: PublicGroupAvatarProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default PublicGroupAvatar;
|
|
9
|
+
//# sourceMappingURL=PublicGroupAvatar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PublicGroupAvatar.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/PublicGroupAvatar.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAMhF,UAAU,sBAAsB;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,2BAA2B,EAAE,CAAC;CACzC;AAKD,QAAA,MAAM,iBAAiB,GAAI,kCAIxB,sBAAsB,4CAwCxB,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Avatar } from "antd";
|
|
4
|
+
import { CONTACT_SEARCH_AVATAR_SIZE, PUBLIC_GROUP_STACKED_AVATAR_SIZE, } from "./constants";
|
|
5
|
+
// Public-group results carry their own member list, so the composite is built
|
|
6
|
+
// from that instead of GroupCompositeAvatar — which fetches members and would
|
|
7
|
+
// fail for a group the seller has not joined yet.
|
|
8
|
+
const PublicGroupAvatar = ({ faceURL, groupName, members = [], }) => {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
if (faceURL) {
|
|
11
|
+
return (_jsx(Avatar, { size: CONTACT_SEARCH_AVATAR_SIZE, src: faceURL, alt: groupName, className: "shrink-0 uppercase", children: (groupName === null || groupName === void 0 ? void 0 : groupName.charAt(0)) || "G" }));
|
|
12
|
+
}
|
|
13
|
+
const [first, second] = members;
|
|
14
|
+
return (_jsxs("div", { className: "relative shrink-0", style: {
|
|
15
|
+
height: CONTACT_SEARCH_AVATAR_SIZE,
|
|
16
|
+
width: CONTACT_SEARCH_AVATAR_SIZE,
|
|
17
|
+
}, children: [_jsx(Avatar, { size: PUBLIC_GROUP_STACKED_AVATAR_SIZE, src: (second === null || second === void 0 ? void 0 : second.faceURL) || undefined, className: "absolute right-0 top-0 border border-white bg-gray-400 uppercase", children: ((_a = second === null || second === void 0 ? void 0 : second.nickname) === null || _a === void 0 ? void 0 : _a.charAt(0)) || (groupName === null || groupName === void 0 ? void 0 : groupName.charAt(0)) || "G" }), _jsx(Avatar, { size: PUBLIC_GROUP_STACKED_AVATAR_SIZE, src: (first === null || first === void 0 ? void 0 : first.faceURL) || undefined, className: "absolute bottom-0 left-0 border border-white bg-gray-400 uppercase", children: ((_b = first === null || first === void 0 ? void 0 : first.nickname) === null || _b === void 0 ? void 0 : _b.charAt(0)) || (groupName === null || groupName === void 0 ? void 0 : groupName.charAt(0)) || "G" })] }));
|
|
18
|
+
};
|
|
19
|
+
export default PublicGroupAvatar;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SearchPublicGroupInfo } from "@droppii-org/wasm-client-sdk";
|
|
2
|
+
interface PublicGroupResultItemProps {
|
|
3
|
+
group: SearchPublicGroupInfo;
|
|
4
|
+
onOpen: (groupID: string) => void;
|
|
5
|
+
}
|
|
6
|
+
declare const PublicGroupResultItem: ({ group, onOpen, }: PublicGroupResultItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default PublicGroupResultItem;
|
|
8
|
+
//# sourceMappingURL=PublicGroupResultItem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PublicGroupResultItem.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/PublicGroupResultItem.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAI1E,UAAU,0BAA0B;IAClC,KAAK,EAAE,qBAAqB,CAAC;IAC7B,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,QAAA,MAAM,qBAAqB,GAAI,oBAG5B,0BAA0B,4CA2E5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import { Spin } from "antd";
|
|
5
|
+
import { useTranslation } from "react-i18next";
|
|
6
|
+
import { useJoinPublicGroup } from "../../../hooks/group/useJoinPublicGroup";
|
|
7
|
+
import PublicGroupAvatar from "./PublicGroupAvatar";
|
|
8
|
+
const PublicGroupResultItem = ({ group, onOpen, }) => {
|
|
9
|
+
var _a, _b;
|
|
10
|
+
const { t } = useTranslation("conversation-inbox");
|
|
11
|
+
const { mutate: joinGroup, isPending } = useJoinPublicGroup();
|
|
12
|
+
// Joined groups open straight away; the rest join first, then open.
|
|
13
|
+
const handleAction = () => {
|
|
14
|
+
if (group.isJoined) {
|
|
15
|
+
onOpen(group.groupID);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
joinGroup({ groupID: group.groupID }, { onSuccess: () => onOpen(group.groupID) });
|
|
19
|
+
};
|
|
20
|
+
return (_jsxs("div", { "data-cp-name": "PublicGroupResultItem", "data-testid": `contact-search-public-group-${group.groupID}`, className: "flex items-center gap-2 border-b border-gray-25 bg-white p-3", children: [_jsxs("button", { type: "button", className: "flex min-w-0 flex-1 items-center gap-2 text-left", onClick: () => onOpen(group.groupID), children: [_jsx(PublicGroupAvatar, { faceURL: group.faceURL, groupName: group.groupName, members: group.members }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-1 pb-0.5", children: [_jsx("span", { className: "truncate text-[16px] font-medium leading-[1.6] text-black", children: group.groupName }), _jsxs("span", { className: "flex min-w-0 flex-col text-[14px] leading-[1.6] tracking-[0.14px] text-gray-600", children: [_jsx("span", { className: "truncate", children: t("contact_search.member_count", {
|
|
21
|
+
count: (_a = group.memberCount) !== null && _a !== void 0 ? _a : 0,
|
|
22
|
+
}) }), _jsx("span", { className: "truncate", children: ((_b = group.introduction) === null || _b === void 0 ? void 0 : _b.trim()) ||
|
|
23
|
+
t("contact_search.public_group_fallback") })] })] })] }), _jsxs("button", { type: "button", disabled: isPending, "data-testid": `contact-search-public-group-action-${group.groupID}`, className: clsx("flex h-7 shrink-0 items-center justify-center gap-2 rounded-lg px-3", "whitespace-nowrap text-center text-[12px] font-medium leading-[1.6] tracking-[0.12px]", group.isJoined
|
|
24
|
+
? "bg-gray-25 text-gray-900"
|
|
25
|
+
: "bg-primary-25 text-primary-400", isPending && "opacity-60"), onClick: handleAction, children: [isPending && _jsx(Spin, { size: "small" }), t(group.isJoined
|
|
26
|
+
? "contact_search.group_access"
|
|
27
|
+
: "contact_search.group_join")] })] }));
|
|
28
|
+
};
|
|
29
|
+
export default PublicGroupResultItem;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { ContactSearchType } from "../../../types/dto";
|
|
2
2
|
export declare const CONTACT_SEARCH_DEBOUNCE_MS = 300;
|
|
3
3
|
export declare const CONTACT_SEARCH_ICON_SIZE = 18;
|
|
4
|
+
export declare const CONTACT_SEARCH_AVATAR_SIZE = 48;
|
|
5
|
+
export declare const PUBLIC_GROUP_STACKED_AVATAR_SIZE = 33;
|
|
4
6
|
export declare const CONTACT_SEARCH_PREVIEW_LIMIT = 5;
|
|
5
7
|
export declare enum ContactSearchTab {
|
|
6
8
|
All = "ALL",
|
|
7
9
|
Contacts = "CONTACTS",
|
|
8
|
-
Messages = "MESSAGES"
|
|
10
|
+
Messages = "MESSAGES",
|
|
11
|
+
Community = "COMMUNITY"
|
|
9
12
|
}
|
|
10
13
|
export declare const CONTACT_SEARCH_TABS: {
|
|
11
14
|
tab: ContactSearchTab;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,eAAO,MAAM,wBAAwB,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAG7C,eAAO,MAAM,gCAAgC,KAAK,CAAC;AAInD,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,oBAAY,gBAAgB;IAC1B,GAAG,QAAQ;IACX,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,SAAS,cAAc;CACxB;AAED,eAAO,MAAM,mBAAmB,EAAE;IAChC,GAAG,EAAE,gBAAgB,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB,EAKA,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE;IACnC,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB,EAKA,CAAC"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { ContactSearchType } from "../../../types/dto";
|
|
2
2
|
export const CONTACT_SEARCH_DEBOUNCE_MS = 300;
|
|
3
3
|
export const CONTACT_SEARCH_ICON_SIZE = 18;
|
|
4
|
+
export const CONTACT_SEARCH_AVATAR_SIZE = 48;
|
|
5
|
+
// The two overlapping circles of the public-group composite avatar.
|
|
6
|
+
export const PUBLIC_GROUP_STACKED_AVATAR_SIZE = 33;
|
|
4
7
|
// `Tất cả` shows a capped preview of the contact section before handing the
|
|
5
8
|
// seller over to the full `Liên hệ` tab.
|
|
6
9
|
export const CONTACT_SEARCH_PREVIEW_LIMIT = 5;
|
|
@@ -9,11 +12,13 @@ export var ContactSearchTab;
|
|
|
9
12
|
ContactSearchTab["All"] = "ALL";
|
|
10
13
|
ContactSearchTab["Contacts"] = "CONTACTS";
|
|
11
14
|
ContactSearchTab["Messages"] = "MESSAGES";
|
|
15
|
+
ContactSearchTab["Community"] = "COMMUNITY";
|
|
12
16
|
})(ContactSearchTab || (ContactSearchTab = {}));
|
|
13
17
|
export const CONTACT_SEARCH_TABS = [
|
|
14
18
|
{ tab: ContactSearchTab.All, labelKey: "contact_search.tabs.all" },
|
|
15
19
|
{ tab: ContactSearchTab.Contacts, labelKey: "contact_search.tabs.contacts" },
|
|
16
20
|
{ tab: ContactSearchTab.Messages, labelKey: "contact_search.tabs.messages" },
|
|
21
|
+
{ tab: ContactSearchTab.Community, labelKey: "contact_search.tabs.community" },
|
|
17
22
|
];
|
|
18
23
|
export const CONTACT_SEARCH_FILTERS = [
|
|
19
24
|
{ type: ContactSearchType.Customer, labelKey: "contact_search.filters.customer" },
|
|
@@ -5,6 +5,8 @@ export { default as ContactSearchStateMessage } from "./ContactSearchStateMessag
|
|
|
5
5
|
export { default as ContactSearchTabs } from "./ContactSearchTabs";
|
|
6
6
|
export { default as ContactSearchSectionHeader } from "./ContactSearchSectionHeader";
|
|
7
7
|
export { default as ContactSearchViewMoreBar } from "./ContactSearchViewMoreBar";
|
|
8
|
+
export { default as PublicGroupResultItem } from "./PublicGroupResultItem";
|
|
9
|
+
export { default as PublicGroupAvatar } from "./PublicGroupAvatar";
|
|
8
10
|
export * from "./constants";
|
|
9
11
|
export * from "./utils";
|
|
10
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACjF,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACnE,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC"}
|
|
@@ -5,5 +5,7 @@ export { default as ContactSearchStateMessage } from "./ContactSearchStateMessag
|
|
|
5
5
|
export { default as ContactSearchTabs } from "./ContactSearchTabs";
|
|
6
6
|
export { default as ContactSearchSectionHeader } from "./ContactSearchSectionHeader";
|
|
7
7
|
export { default as ContactSearchViewMoreBar } from "./ContactSearchViewMoreBar";
|
|
8
|
+
export { default as PublicGroupResultItem } from "./PublicGroupResultItem";
|
|
9
|
+
export { default as PublicGroupAvatar } from "./PublicGroupAvatar";
|
|
8
10
|
export * from "./constants";
|
|
9
11
|
export * from "./utils";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAgCA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAgCA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAwT3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -160,6 +160,8 @@ const MessageList = (props) => {
|
|
|
160
160
|
if (!conversationData) {
|
|
161
161
|
return (_jsx("div", { className: "flex flex-1 items-center justify-center h-full", children: connectStatus !== ConnectStatus.Connected ? (_jsx(Spin, {})) : (_jsx(Empty, { description: t("no_conversation_data") })) }));
|
|
162
162
|
}
|
|
163
|
-
return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full min-w-0 bg-white", style: { overflowX: "hidden" }, "data-cp-name": "MessageList", children: [_jsx(MessageHeader, { onClose: onClose, currentSession: latestConversationSession, isJoined: isJoined, onOpenThreadInfo: onOpenThreadInfo }), _jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array, isGroupChat: isGroupChat, contextMenuOpen: openMenuId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenMenuId(open ? message.clientMsgID : null), onRevokeMessage: handleOpenRevoke, onQuoteMessage: setQuotedMessage, onPressQuoteMessage: onPressQuoteMessage, onPinMessage: canPinMessage ? handlePinMessage : undefined, onUnpinMessage: canPinMessage ? handleUnpinMessage : undefined }, message.clientMsgID))) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), (isGroupChat && isCheckingMembership) || !isGroupStateFresh ? (_jsx("div", { className: "border-t bg-white py-4 flex items-center justify-center", children: _jsx(Spin, {}) })) :
|
|
163
|
+
return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full min-w-0 bg-white", style: { overflowX: "hidden" }, "data-cp-name": "MessageList", children: [_jsx(MessageHeader, { onClose: onClose, currentSession: latestConversationSession, isJoined: isJoined, onOpenThreadInfo: onOpenThreadInfo }), _jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array, isGroupChat: isGroupChat, contextMenuOpen: openMenuId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenMenuId(open ? message.clientMsgID : null), onRevokeMessage: handleOpenRevoke, onQuoteMessage: setQuotedMessage, onPressQuoteMessage: onPressQuoteMessage, onPinMessage: canPinMessage ? handlePinMessage : undefined, onUnpinMessage: canPinMessage ? handleUnpinMessage : undefined }, message.clientMsgID))) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), (isGroupChat && isCheckingMembership) || !isGroupStateFresh ? (_jsx("div", { className: "border-t bg-white py-4 flex items-center justify-center", children: _jsx(Spin, {}) })) : (latestConversationSession === null || latestConversationSession === void 0 ? void 0 : latestConversationSession.status) === SessionStatus.UNASSIGNED ? (_jsx(UnassignedSessionFooter, { sessionId: latestConversationSession.id, teamId: latestConversationSession.teamId })) : shouldRestrictToLastSession ? (_jsxs("div", { className: "border-t bg-white py-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-sm text-gray-500", children: t("join_group_required") }), _jsx(Button, { type: "primary", onClick: joinGroup, loading: isJoining, children: t("join_group") })] })) : isViewOnlyMember ? (
|
|
164
|
+
// Brief fallback while isJoined catches up after the kick event.
|
|
165
|
+
_jsx(MessageFooter, { currentSession: latestConversationSession, openCreateCannedModal: openCreateCannedModal })) : !canSendMessage ? (_jsx("div", { className: "border-t bg-[#f5f5f5] py-3 flex items-center justify-center", children: _jsx("p", { className: "text-sm text-gray-500", children: t(isRestrictedByGroupMute ? "send_message_disabled_group_mute" : "send_message_disabled") }) })) : (_jsx(MessageFooter, { currentSession: latestConversationSession, openCreateCannedModal: openCreateCannedModal })), _jsx(ConfirmModal, { open: showConfirmRevoke, onOk: onRevokeMessage, onCancel: handleCloseRevoke, title: t("revoke_message_confirm_title"), okText: t("revoke"), cancelText: t("cancel"), okType: "danger", confirmLoading: isRevoking, children: _jsx("p", { children: t("revoke_message_confirm_message") }) }), _jsx(PinLimitModal, { open: pinLimitModalOpen, max: pinnedTotalCount, onClose: () => setPinLimitModalOpen(false) })] }));
|
|
164
166
|
};
|
|
165
167
|
export default MessageList;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAGL,wBAAwB,EAEzB,MAAM,cAAc,CAAC;AAStB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAoB/C,UAAU,kBAAkB;IAC1B,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AASD,eAAO,MAAM,oBAAoB,mDAc/B,CAAC;AAEH,eAAO,MAAM,uBAAuB,gCAAyC,CAAC;AAE9E,QAAA,MAAM,qBAAqB,GAAI,4CAG5B,kBAAkB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAGL,wBAAwB,EAEzB,MAAM,cAAc,CAAC;AAStB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAoB/C,UAAU,kBAAkB;IAC1B,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AASD,eAAO,MAAM,oBAAoB,mDAc/B,CAAC;AAEH,eAAO,MAAM,uBAAuB,gCAAyC,CAAC;AAE9E,QAAA,MAAM,qBAAqB,GAAI,4CAG5B,kBAAkB,4CA0UpB,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -27,7 +27,7 @@ import useConversationStore from "../../../store/conversation";
|
|
|
27
27
|
import { useCurrentUserAccountType } from "../../../hooks/user/useCurrentUserAccountType";
|
|
28
28
|
import ComposerTabs from "./ComposerTabs";
|
|
29
29
|
import ComposerEditor from "./ComposerEditor";
|
|
30
|
-
import MentionMenu from "./mention/MentionMenu";
|
|
30
|
+
import MentionMenu, { COMPOSER_AREA_CP_NAME } from "./mention/MentionMenu";
|
|
31
31
|
import SessionClosedModal from "./SessionClosedModal";
|
|
32
32
|
import { useCreateSession, useReopenSession, } from "../../../hooks/session/useReopenOrCreateSession";
|
|
33
33
|
import { emit } from "../../../utils/events";
|
|
@@ -234,6 +234,6 @@ const MessageFooterProvider = ({ currentSession, openCreateCannedModal, }) => {
|
|
|
234
234
|
setIsMentionMenuOpen,
|
|
235
235
|
}, children: [_jsxs(LexicalComposer, { initialConfig: initialConfig, children: [_jsx(Popover, { open: isOpenCanned, content: _jsx(CannedResponse, { onClose: closeCanned, openCreateCannedModal: onOpenCreateCannedModal, cannedQuery: cannedQuery }), placement: "topLeft", trigger: "click", arrow: false, classNames: {
|
|
236
236
|
body: "mx-1 !p-0",
|
|
237
|
-
}, destroyOnHidden: true, children: _jsxs("div", { className: "border-t pb-2 flex flex-col gap-1 bg-white", children: [_jsx(ReplyPreviewBar, {}), listUploadFiles.length > 0 && _jsx(FilePreview, {}), showLinkPreview && previewUrl && (_jsx(LinkInputPreview, { url: previewUrl, onRemove: () => setIsLinkPreviewDismissed(true) })), _jsx(ToolbarPlugin, {}), _jsxs("div", { children: [_jsx(ComposerTabs, { canUseInternal: canUseInternal, hintText: t("canned_response_hint"), isInternal: isInternal, lockToInternal: lockToInternal, setIsInternal: setIsInternal }), _jsx(ComposerEditor, { isInternal: isInternal, placeholderText: placeholderText })] }), _jsx(ActionBar, {})] }) }), _jsx(LinkPlugin, {}), _jsx(ListPlugin, {}), _jsx(ComposerTextSyncPlugin, { onChange: setComposerText }), _jsx(EnterHandler, {}), _jsx(PasteAndDropPlugin, {}), isGroupConversation(conversationData !== null && conversationData !== void 0 ? conversationData : undefined) && (_jsx(MentionMenu, { groupID: conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID })), isCrm && (_jsx(CannedResponseTriggerPlugin, { onClose: closeCanned, onOpen: onOpenCanned }))] }), _jsx(SessionClosedModal, { open: isSessionClosedModalOpen, loading: isSessionActionLoading, onReopen: handleReopenSession, onCreateNew: handleCreateNewSession, onClose: handleCloseSessionModal })] }));
|
|
237
|
+
}, destroyOnHidden: true, children: _jsxs("div", { "data-cp-name": COMPOSER_AREA_CP_NAME, className: "border-t pb-2 flex flex-col gap-1 bg-white", children: [_jsx(ReplyPreviewBar, {}), listUploadFiles.length > 0 && _jsx(FilePreview, {}), showLinkPreview && previewUrl && (_jsx(LinkInputPreview, { url: previewUrl, onRemove: () => setIsLinkPreviewDismissed(true) })), _jsx(ToolbarPlugin, {}), _jsxs("div", { children: [_jsx(ComposerTabs, { canUseInternal: canUseInternal, hintText: t("canned_response_hint"), isInternal: isInternal, lockToInternal: lockToInternal, setIsInternal: setIsInternal }), _jsx(ComposerEditor, { isInternal: isInternal, placeholderText: placeholderText })] }), _jsx(ActionBar, {})] }) }), _jsx(LinkPlugin, {}), _jsx(ListPlugin, {}), _jsx(ComposerTextSyncPlugin, { onChange: setComposerText }), _jsx(EnterHandler, {}), _jsx(PasteAndDropPlugin, {}), isGroupConversation(conversationData !== null && conversationData !== void 0 ? conversationData : undefined) && (_jsx(MentionMenu, { groupID: conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID })), isCrm && (_jsx(CannedResponseTriggerPlugin, { onClose: closeCanned, onOpen: onOpenCanned }))] }), _jsx(SessionClosedModal, { open: isSessionClosedModalOpen, loading: isSessionActionLoading, onReopen: handleReopenSession, onCreateNew: handleCreateNewSession, onClose: handleCloseSessionModal })] }));
|
|
238
238
|
};
|
|
239
239
|
export default MessageFooterProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MentionMenu.d.ts","sourceRoot":"","sources":["../../../../../src/components/message/footer/mention/MentionMenu.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MentionMenu.d.ts","sourceRoot":"","sources":["../../../../../src/components/message/footer/mention/MentionMenu.tsx"],"names":[],"mappings":"AA8BA,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AAWjE,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED,QAAA,MAAM,WAAW,GAAI,aAAa,gBAAgB,mDAyIjD,CAAC;AA+CF,eAAe,WAAW,CAAC"}
|
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
2
13
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useCallback, useMemo, useState } from "react";
|
|
14
|
+
import { useCallback, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
4
15
|
import { createPortal } from "react-dom";
|
|
5
16
|
import { useTranslation } from "react-i18next";
|
|
6
17
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
7
18
|
import { LexicalTypeaheadMenuPlugin, MenuOption, useBasicTypeaheadTriggerMatch, } from "@lexical/react/LexicalTypeaheadMenuPlugin";
|
|
8
19
|
import { $createTextNode, $getRoot } from "lexical";
|
|
9
|
-
import { $createMentionNode, $
|
|
20
|
+
import { $createMentionNode, $getMentionedUserIDs } from "./MentionNode";
|
|
10
21
|
import { useMentionOptions } from "./useMentionOptions";
|
|
11
22
|
import { Avatar } from "antd";
|
|
12
23
|
import { useMessageFooterContext } from "..";
|
|
13
24
|
const MAX_MENTIONED_USERS = 10;
|
|
25
|
+
// Marks the composer's outer boundary (footer/index.tsx) so
|
|
26
|
+
// MentionMenuOffset below can measure against it despite Lexical's
|
|
27
|
+
// typeahead container being portaled outside the composer's own DOM
|
|
28
|
+
// subtree. Exported so both sides of this coupling share one literal.
|
|
29
|
+
export const COMPOSER_AREA_CP_NAME = "MessageFooterComposerArea";
|
|
14
30
|
class MentionTypeaheadOption extends MenuOption {
|
|
15
31
|
constructor(option) {
|
|
16
32
|
super(option.userID);
|
|
@@ -28,11 +44,18 @@ const MentionMenu = ({ groupID }) => {
|
|
|
28
44
|
const options = useMentionOptions(groupID, query !== null && query !== void 0 ? query : "");
|
|
29
45
|
// Re-evaluated per query change (menu re-opens/re-queries on every "@"),
|
|
30
46
|
// so this stays in sync with mentions added/removed since the last count.
|
|
31
|
-
const
|
|
47
|
+
const mentionedUserIDs = useMemo(() => editor.getEditorState().read(() => $getMentionedUserIDs($getRoot())), [editor, query]);
|
|
48
|
+
const mentionedUsersCount = mentionedUserIDs.size;
|
|
32
49
|
const limitReached = mentionedUsersCount >= MAX_MENTIONED_USERS;
|
|
50
|
+
// Already-tagged users don't need to appear again in the same draft.
|
|
33
51
|
// "Tất cả" doesn't count against the per-user cap and stays selectable;
|
|
34
52
|
// only specific-member options are hidden once the limit is hit.
|
|
35
|
-
const visibleOptions = useMemo(() =>
|
|
53
|
+
const visibleOptions = useMemo(() => {
|
|
54
|
+
const notYetMentioned = options.filter((option) => option.isAtAll || !mentionedUserIDs.has(option.userID));
|
|
55
|
+
return limitReached
|
|
56
|
+
? notYetMentioned.filter((option) => option.isAtAll)
|
|
57
|
+
: notYetMentioned;
|
|
58
|
+
}, [options, mentionedUserIDs, limitReached]);
|
|
36
59
|
const typeaheadOptions = useMemo(() => visibleOptions.map((option) => new MentionTypeaheadOption(option)), [visibleOptions]);
|
|
37
60
|
const onSelectOption = useCallback((selected, textNodeContainingQuery, closeMenu) => {
|
|
38
61
|
editor.update(() => {
|
|
@@ -60,10 +83,47 @@ const MentionMenu = ({ groupID }) => {
|
|
|
60
83
|
// that much room, so it always renders downward and gets clipped
|
|
61
84
|
// by the page. Anchoring this menu to the container's bottom
|
|
62
85
|
// edge instead makes it grow upward from the caret line
|
|
63
|
-
// unconditionally, independent of that flip heuristic.
|
|
64
|
-
|
|
86
|
+
// unconditionally, independent of that flip heuristic. But the
|
|
87
|
+
// caret line itself sits inside the composer box (it's the text
|
|
88
|
+
// cursor position), not above it — so "grow up from here" still
|
|
89
|
+
// overlapped the composer's own top portion. MentionMenuOffset
|
|
90
|
+
// pushes the extra distance from the caret up to the composer's
|
|
91
|
+
// actual top edge, so the menu clears the input entirely.
|
|
92
|
+
_jsxs(MentionMenuOffset, { "data-cp-name": "MentionMenu", className: "absolute left-0 z-50 max-h-[220px] w-[260px] overflow-y-auto rounded-md border border-gray-200 bg-white py-1 shadow-lg", children: [_jsx("div", { className: "px-3 py-1 text-xs font-medium text-gray-400", children: t("mention.menu_title") }), typeaheadOptions.length === 0 ? (_jsx("div", { className: "px-3 py-2 text-sm text-gray-500", children: limitReached
|
|
65
93
|
? t("mention.limit_reached", { max: MAX_MENTIONED_USERS })
|
|
66
94
|
: t("mention.no_result") })) : (typeaheadOptions.map((option, index) => (_jsxs("button", { type: "button", className: `flex w-full items-center gap-2 px-3 py-2 text-left text-sm ${index === selectedIndex ? "bg-blue-50" : "hover:bg-gray-50"}`, onMouseEnter: () => setHighlightedIndex(index), onClick: () => selectOptionAndCleanUp(option), children: [option.option.isAtAll ? (_jsx("span", { className: "flex h-6 w-6 shrink-0 items-center justify-center rounded-full bg-gray-100 text-gray-500", children: "@" })) : (_jsx(Avatar, { size: 24, src: option.option.faceURL, children: option.option.displayName.charAt(0) })), _jsx("span", { className: "min-w-0 flex-1 truncate", children: option.option.displayName })] }, option.key))))] }), anchorElementRef.current);
|
|
67
95
|
} }));
|
|
68
96
|
};
|
|
97
|
+
// Renders inside Lexical's own typeahead container, which it portals
|
|
98
|
+
// straight to document.body — detached from the composer's own DOM
|
|
99
|
+
// subtree, so `closest()` can't find the composer from here. Look it up
|
|
100
|
+
// globally instead: only one composer is ever focused/active at a time.
|
|
101
|
+
// Measures the distance from the caret-position anchor up to the
|
|
102
|
+
// composer's top edge and applies it as `bottom`, so the menu's own bottom
|
|
103
|
+
// edge lands there instead of at the caret's — clearing the input instead
|
|
104
|
+
// of overlapping it.
|
|
105
|
+
//
|
|
106
|
+
// No dependency array: this component's identity survives across the
|
|
107
|
+
// re-renders LexicalTypeaheadMenuPlugin fires on every keystroke while the
|
|
108
|
+
// menu stays open (same tree position, not remounted), so a one-time
|
|
109
|
+
// measurement would go stale the moment the composer's own height changes
|
|
110
|
+
// mid-session (e.g. a reply preview or file attachment toggling on/off).
|
|
111
|
+
// Re-measuring every render keeps it correct at the cost of one cheap
|
|
112
|
+
// getBoundingClientRect() call per keystroke.
|
|
113
|
+
const MentionMenuOffset = (_a) => {
|
|
114
|
+
var { className, children } = _a, rest = __rest(_a, ["className", "children"]);
|
|
115
|
+
const ref = useRef(null);
|
|
116
|
+
const [bottomOffset, setBottomOffset] = useState(0);
|
|
117
|
+
useLayoutEffect(() => {
|
|
118
|
+
var _a;
|
|
119
|
+
const anchorNode = (_a = ref.current) === null || _a === void 0 ? void 0 : _a.parentElement;
|
|
120
|
+
const composer = document.querySelector(`[data-cp-name="${COMPOSER_AREA_CP_NAME}"]`);
|
|
121
|
+
if (!anchorNode || !composer)
|
|
122
|
+
return;
|
|
123
|
+
const anchorRect = anchorNode.getBoundingClientRect();
|
|
124
|
+
const composerRect = composer.getBoundingClientRect();
|
|
125
|
+
setBottomOffset(Math.max(0, anchorRect.top - composerRect.top));
|
|
126
|
+
});
|
|
127
|
+
return (_jsx("div", Object.assign({ ref: ref, className: className, style: { bottom: bottomOffset } }, rest, { children: children })));
|
|
128
|
+
};
|
|
69
129
|
export default MentionMenu;
|
|
@@ -17,5 +17,5 @@ export declare class MentionNode extends TextNode {
|
|
|
17
17
|
}
|
|
18
18
|
export declare function $createMentionNode(userID: string, isAtAll: boolean, displayText: string): MentionNode;
|
|
19
19
|
export declare function $isMentionNode(node: LexicalNode | null | undefined): node is MentionNode;
|
|
20
|
-
export declare function $
|
|
20
|
+
export declare function $getMentionedUserIDs(root: LexicalNode): Set<string>;
|
|
21
21
|
//# sourceMappingURL=MentionNode.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MentionNode.d.ts","sourceRoot":"","sources":["../../../../../src/components/message/footer/mention/MentionNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,kBAAkB,EACvB,KAAK,MAAM,EACZ,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,qBAAqB,GAAG,MAAM,CACxC;IACE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,EACD,kBAAkB,CACnB,CAAC;AAEF,qBAAa,WAAY,SAAQ,QAAQ;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IAEnB,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW;gBAU1C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,OAAO;IAOf,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAM5C,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,qBAAqB,GAAG,WAAW;IAQrE,UAAU,IAAI,qBAAqB;IASnC,mBAAmB,IAAI,OAAO;IAI9B,YAAY,IAAI,IAAI;CAGrB;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,MAAM,GAClB,WAAW,CAIb;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GACnC,IAAI,IAAI,WAAW,CAErB;AAID,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"MentionNode.d.ts","sourceRoot":"","sources":["../../../../../src/components/message/footer/mention/MentionNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,QAAQ,EACR,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,kBAAkB,EACvB,KAAK,MAAM,EACZ,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,qBAAqB,GAAG,MAAM,CACxC;IACE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,EACD,kBAAkB,CACnB,CAAC;AAEF,qBAAa,WAAY,SAAQ,QAAQ;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IAEnB,MAAM,CAAC,OAAO,IAAI,MAAM;IAIxB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW;gBAU1C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,OAAO;IAOf,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW;IAM5C,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,qBAAqB,GAAG,WAAW;IAQrE,UAAU,IAAI,qBAAqB;IASnC,mBAAmB,IAAI,OAAO;IAI9B,YAAY,IAAI,IAAI;CAGrB;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,MAAM,GAClB,WAAW,CAIb;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,GACnC,IAAI,IAAI,WAAW,CAErB;AAID,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,CAcnE"}
|
|
@@ -39,7 +39,7 @@ export function $isMentionNode(node) {
|
|
|
39
39
|
}
|
|
40
40
|
// Distinct specific users tagged so far — "Tất cả" (isAtAll) mentions aren't
|
|
41
41
|
// individual users and don't count toward the per-user cap.
|
|
42
|
-
export function $
|
|
42
|
+
export function $getMentionedUserIDs(root) {
|
|
43
43
|
const userIDs = new Set();
|
|
44
44
|
const walk = (node) => {
|
|
45
45
|
if ($isMentionNode(node) && !node.__isAtAll) {
|
|
@@ -50,5 +50,5 @@ export function $countMentionedUsers(root) {
|
|
|
50
50
|
}
|
|
51
51
|
};
|
|
52
52
|
walk(root);
|
|
53
|
-
return userIDs
|
|
53
|
+
return userIDs;
|
|
54
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMentionOptions.d.ts","sourceRoot":"","sources":["../../../../../src/components/message/footer/mention/useMentionOptions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useMentionOptions.d.ts","sourceRoot":"","sources":["../../../../../src/components/message/footer/mention/useMentionOptions.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAW7C,eAAO,MAAM,iBAAiB,GAC5B,SAAS,MAAM,GAAG,SAAS,EAC3B,OAAO,MAAM,KACZ,aAAa,EAyCf,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
2
|
import { useTranslation } from "react-i18next";
|
|
3
3
|
import { useGroupMembers } from "../../../../hooks/group/useGroupMembers";
|
|
4
|
+
import useAuthStore from "../../../../store/auth";
|
|
4
5
|
export const ALL_MEMBERS_USER_ID = "__all__";
|
|
5
6
|
// Prefix matches rank above mid-string matches, then alphabetical — matches
|
|
6
7
|
// the "closest match first" ranking spec'd for this feature (not just a
|
|
@@ -14,11 +15,13 @@ const matchRank = (displayName, keyword) => {
|
|
|
14
15
|
export const useMentionOptions = (groupID, query) => {
|
|
15
16
|
const { t } = useTranslation();
|
|
16
17
|
const { members } = useGroupMembers(groupID);
|
|
18
|
+
const currentUserID = useAuthStore((state) => state.userID);
|
|
17
19
|
return useMemo(() => {
|
|
18
20
|
const keyword = query.trim().toLowerCase();
|
|
19
|
-
// Self-tagging
|
|
20
|
-
//
|
|
21
|
+
// Self-tagging isn't a useful mention target — the sender already
|
|
22
|
+
// knows who they are — so the current user is filtered out entirely.
|
|
21
23
|
const memberOptions = members
|
|
24
|
+
.filter((member) => member.userID !== currentUserID)
|
|
22
25
|
.map((member) => ({
|
|
23
26
|
userID: member.userID,
|
|
24
27
|
displayName: member.nickname || member.userID,
|
|
@@ -41,5 +44,5 @@ export const useMentionOptions = (groupID, query) => {
|
|
|
41
44
|
};
|
|
42
45
|
const matchesAll = !keyword || allOption.displayName.toLowerCase().includes(keyword);
|
|
43
46
|
return matchesAll ? [allOption, ...memberOptions] : memberOptions;
|
|
44
|
-
}, [members, query, t]);
|
|
47
|
+
}, [members, query, t, currentUserID]);
|
|
45
48
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/index.tsx"],"names":[],"mappings":"AAWA,oBAAY,wBAAwB;IAClC,GAAG,QAAQ;IACX,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,QAAQ,aAAa;IACrB,MAAM,WAAW;CAClB;AAED,UAAU,uBAAuB;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AACD,QAAA,MAAM,kBAAkB,GAAI,gBAAgB,uBAAuB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/index.tsx"],"names":[],"mappings":"AAWA,oBAAY,wBAAwB;IAClC,GAAG,QAAQ;IACX,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,QAAQ,aAAa;IACrB,MAAM,WAAW;CAClB;AAED,UAAU,uBAAuB;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AACD,QAAA,MAAM,kBAAkB,GAAI,gBAAgB,uBAAuB,4CA4ElE,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|