@droppii-org/chat-sdk 0.7.6 → 0.7.7
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-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/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/package.json +1 -1
|
@@ -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) {
|
|
@@ -6,6 +6,7 @@ interface UseSearchPublicGroupsParams {
|
|
|
6
6
|
}
|
|
7
7
|
export declare const useSearchPublicGroups: ({ searchTerm, enabled, pageSize, }: UseSearchPublicGroupsParams) => {
|
|
8
8
|
groups: SearchPublicGroupInfo[];
|
|
9
|
+
total: number;
|
|
9
10
|
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("@droppii-org/wasm-client-sdk").SearchPublicGroupsResult, unknown>, Error>>;
|
|
10
11
|
hasNextPage: boolean;
|
|
11
12
|
isFetchingNextPage: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSearchPublicGroups.d.ts","sourceRoot":"","sources":["../../../src/hooks/search/useSearchPublicGroups.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,8BAA8B,CAAC;AAKtC,UAAU,2BAA2B;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAKD,eAAO,MAAM,qBAAqB,GAAI,oCAInC,2BAA2B
|
|
1
|
+
{"version":3,"file":"useSearchPublicGroups.d.ts","sourceRoot":"","sources":["../../../src/hooks/search/useSearchPublicGroups.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,8BAA8B,CAAC;AAKtC,UAAU,2BAA2B;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAKD,eAAO,MAAM,qBAAqB,GAAI,oCAInC,2BAA2B;;;;;;;;CA0D7B,CAAC"}
|
|
@@ -9,6 +9,7 @@ import { PAGE_SIZE } from "../../constants";
|
|
|
9
9
|
// same call chat-mobile uses for its `Cộng đồng` tab, so both platforms return
|
|
10
10
|
// the identical public-group set (joined and not yet joined).
|
|
11
11
|
export const useSearchPublicGroups = ({ searchTerm, enabled = true, pageSize = PAGE_SIZE.medium, }) => {
|
|
12
|
+
var _a, _b, _c;
|
|
12
13
|
const trimmedSearchTerm = searchTerm.trim();
|
|
13
14
|
const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading, isError } = useInfiniteQuery({
|
|
14
15
|
initialPageParam: 0,
|
|
@@ -29,6 +30,9 @@ export const useSearchPublicGroups = ({ searchTerm, enabled = true, pageSize = P
|
|
|
29
30
|
return fetched < ((_a = lastPage === null || lastPage === void 0 ? void 0 : lastPage.total) !== null && _a !== void 0 ? _a : 0) ? fetched : undefined;
|
|
30
31
|
},
|
|
31
32
|
enabled: enabled && trimmedSearchTerm !== "",
|
|
33
|
+
// `Tất cả` waits for this query, so a failing engine must not hold it
|
|
34
|
+
// through the default three retries.
|
|
35
|
+
retry: 1,
|
|
32
36
|
});
|
|
33
37
|
// A group can repeat across offsets while the backing list shifts.
|
|
34
38
|
const groups = useMemo(() => {
|
|
@@ -46,6 +50,8 @@ export const useSearchPublicGroups = ({ searchTerm, enabled = true, pageSize = P
|
|
|
46
50
|
}, [data]);
|
|
47
51
|
return {
|
|
48
52
|
groups,
|
|
53
|
+
// Every page carries the same server-side total for the keyword.
|
|
54
|
+
total: (_c = (_b = (_a = data === null || data === void 0 ? void 0 : data.pages) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.total) !== null && _c !== void 0 ? _c : 0,
|
|
49
55
|
fetchNextPage,
|
|
50
56
|
hasNextPage,
|
|
51
57
|
isFetchingNextPage,
|