@droppii-org/chat-sdk 0.7.22 → 0.8.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"GroupMembersDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/message/GroupMembersDrawer.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA6B/C,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA6BD,QAAA,MAAM,kBAAkB,GAAI,wDAKzB,uBAAuB,4CA6rBzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"GroupMembersDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/message/GroupMembersDrawer.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA8B/C,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA6BD,QAAA,MAAM,kBAAkB,GAAI,wDAKzB,uBAAuB,4CAusBzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -26,6 +26,7 @@ import useDeskPanelHostStore from "../../store/deskPanelHost";
26
26
  import DeskSidePanel from "../../components/common/DeskSidePanel";
27
27
  import GroupMembersPanelCrm from "./GroupMembersPanelCrm";
28
28
  import { buildCrmMemberMenu } from "./groupMemberMenuCrm";
29
+ import { useUsersUsernames } from "../../hooks/user/useUserUsername";
29
30
  // A group's list loads page by page as the reader scrolls.
30
31
  const MEMBER_PAGE_SIZE = 50;
31
32
  const LOAD_MORE_THRESHOLD_PX = 80;
@@ -104,6 +105,8 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
104
105
  ? [actingMember, ...members]
105
106
  : members, [isPagedList, actingMember, members]);
106
107
  const sourceMembers = isSearchActive ? searchResults : listedMembers;
108
+ // Looked up only while the list is open: the drawer stays mounted in every thread header.
109
+ const usernames = useUsersUsernames(isOpen ? sourceMembers.map((member) => member.userID) : []);
107
110
  const sortedMembers = useMemo(() => {
108
111
  return [...sourceMembers]
109
112
  .map((member) => {
@@ -114,6 +117,7 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
114
117
  return {
115
118
  userID: member.userID,
116
119
  nickname: getMemberDisplayName(member),
120
+ username: usernames[member.userID],
117
121
  faceURL: member.faceURL,
118
122
  isCustomer: Boolean(customerUserID) && member.userID === customerUserID,
119
123
  isCurrentUser: member.userID === authUserID,
@@ -148,7 +152,7 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
148
152
  sensitivity: "base",
149
153
  });
150
154
  });
151
- }, [authUserID, sourceMembers, customerUserID, t, isPagedList, isSearchActive]);
155
+ }, [authUserID, sourceMembers, usernames, customerUserID, t, isPagedList, isSearchActive]);
152
156
  const handleListScroll = (event) => {
153
157
  if (isSearchActive || !hasMore || isLoadingMore)
154
158
  return;
@@ -430,7 +434,7 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
430
434
  disabled: true,
431
435
  },
432
436
  ];
433
- return (_jsxs("div", { className: "flex items-center gap-3 px-4 py-2", children: [_jsx(Avatar, { src: member.faceURL, size: 40, className: "shrink-0", children: member.nickname.charAt(0) || "A" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("p", { className: "text-sm font-semibold text-gray-900 truncate", children: member.nickname }), member.isCurrentUser && (_jsx("span", { className: "text-xs text-blue-500 shrink-0", children: t("current_account") }))] }), member.roleLabel && (_jsx("p", { className: "text-sm text-gray-500 truncate", children: member.roleLabel }))] }), (isRealGroup || member.isCurrentUser) && (_jsx(Dropdown, { menu: { items: menuItems }, trigger: ["click"], placement: "bottomRight", children: _jsx("button", { type: "button", "aria-label": t("member_actions"), title: t("member_actions"), className: "flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:bg-gray-100", onClick: (event) => event.stopPropagation(), children: _jsx(Icon, { icon: "more-horizontal-b", size: 18 }) }) }))] }, member.userID));
437
+ return (_jsxs("div", { className: "flex items-center gap-3 px-4 py-2", children: [_jsx(Avatar, { src: member.faceURL, size: 40, className: "shrink-0", children: member.nickname.charAt(0) || "A" }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("p", { className: "text-sm font-semibold text-gray-900 truncate", children: member.nickname }), member.isCurrentUser && (_jsx("span", { className: "text-xs text-blue-500 shrink-0", children: t("current_account") }))] }), member.username && (_jsx("p", { className: "text-xs text-gray-500 truncate", title: member.username, children: member.username })), member.roleLabel && (_jsx("p", { className: "text-sm text-gray-500 truncate", children: member.roleLabel }))] }), (isRealGroup || member.isCurrentUser) && (_jsx(Dropdown, { menu: { items: menuItems }, trigger: ["click"], placement: "bottomRight", children: _jsx("button", { type: "button", "aria-label": t("member_actions"), title: t("member_actions"), className: "flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:bg-gray-100", onClick: (event) => event.stopPropagation(), children: _jsx(Icon, { icon: "more-horizontal-b", size: 18 }) }) }))] }, member.userID));
434
438
  }) }));
435
439
  };
436
440
  return (_jsxs("div", { className: "inline-flex shrink-0", "data-cp-name": "GroupMembersDrawer", children: [_jsx(Button, { ref: triggerRef, type: "text", shape: "default", className: headerIconButtonClass(isCrm, isOpen), onClick: handleOpenDrawer, disabled: disabled || !groupID, "aria-label": t("members"), title: t("members"), children: _jsx(HeaderIcon, { isCrm: isCrm, stroke: "users", font: "user-two-check-o" }) }), isCrm && (host.workspace || host.slot) ? (renderCrmHost()) : (_jsx(Drawer, { open: isOpen, "aria-label": t("members"), onClose: handleCloseDrawer, mask: false, closeIcon: false, styles: {
@@ -1 +1 @@
1
- {"version":3,"file":"GroupMembersPanelCrm.d.ts","sourceRoot":"","sources":["../../../src/components/message/GroupMembersPanelCrm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA4B,OAAO,EAAE,MAAM,OAAO,CAAC;AAE/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAMtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,UAAU,yBAAyB;IACjC,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,mFAAmF;IACnF,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,oEAAoE;IACpE,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,SAAS,CAAC,OAAO,CAAC,CAAC;CAC9D;AAQD,gGAAgG;AAChG,QAAA,MAAM,oBAAoB,GAAI,4LAgB3B,yBAAyB,4CAiI3B,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"GroupMembersPanelCrm.d.ts","sourceRoot":"","sources":["../../../src/components/message/GroupMembersPanelCrm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA4B,OAAO,EAAE,MAAM,OAAO,CAAC;AAE/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAMtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,UAAU,yBAAyB;IACjC,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,mFAAmF;IACnF,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,oEAAoE;IACpE,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,SAAS,CAAC,OAAO,CAAC,CAAC;CAC9D;AAQD,gGAAgG;AAChG,QAAA,MAAM,oBAAoB,GAAI,4LAgB3B,yBAAyB,4CAwI3B,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -39,7 +39,7 @@ const GroupMembersPanelCrm = ({ totalCount, members, isRealGroup, isLoading, isL
39
39
  : member.isAdmin
40
40
  ? _jsx("span", { className: `${CHIP} bg-gray-25 text-gray-900`, children: t("group_admin") })
41
41
  : null;
42
- return (_jsxs("li", { className: "flex items-center gap-2.5 rounded-lg p-2", children: [_jsx(PersonAvatar, { name: member.nickname, src: member.faceURL, size: 36 }), _jsxs("span", { className: "flex min-w-0 flex-1 items-baseline gap-1 text-sm font-medium text-gray-900", children: [_jsx("span", { className: "truncate", title: member.nickname, children: member.nickname }), member.isCurrentUser && (_jsxs("span", { className: "shrink-0 text-xs font-normal text-gray-600", children: ["(", t("you"), ")"] }))] }), roleChip, member.isSendMessageDisabled && !member.isOwner && (_jsxs("span", { className: `${CHIP} bg-warning-25 text-warning-800`, children: [_jsx(Icon, { icon: "bell-off-o", size: 12 }), t("send_disabled_chip")] })), items && items.length > 0 && (_jsx(Dropdown, { menu: { items, style: { width: 260 } }, trigger: ["click"], placement: "bottomRight", children: _jsx("button", { type: "button", "aria-label": t("member_actions_for", { name: member.nickname }), title: t("member_actions_for", { name: member.nickname }), className: `flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-gray-600 hover:bg-gray-5 aria-expanded:bg-gray-25 aria-expanded:text-gray-900 ${FOCUS_RING_CLASS}`, children: _jsx(Icon, { icon: "more-horizontal-b", size: 18 }) }) }))] }, member.userID));
42
+ return (_jsxs("li", { className: "flex items-center gap-2.5 rounded-lg p-2", children: [_jsx(PersonAvatar, { name: member.nickname, src: member.faceURL, size: 36 }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [_jsxs("span", { className: "flex min-w-0 items-baseline gap-1 text-sm font-medium text-gray-900", children: [_jsx("span", { className: "truncate", title: member.nickname, children: member.nickname }), member.isCurrentUser && (_jsxs("span", { className: "shrink-0 text-xs font-normal text-gray-600", children: ["(", t("you"), ")"] }))] }), member.username && (_jsx("span", { className: "truncate text-xs leading-4 text-gray-600", title: member.username, children: member.username }))] }), roleChip, member.isSendMessageDisabled && !member.isOwner && (_jsxs("span", { className: `${CHIP} bg-warning-25 text-warning-800`, children: [_jsx(Icon, { icon: "bell-off-o", size: 12 }), t("send_disabled_chip")] })), items && items.length > 0 && (_jsx(Dropdown, { menu: { items, style: { width: 260 } }, trigger: ["click"], placement: "bottomRight", children: _jsx("button", { type: "button", "aria-label": t("member_actions_for", { name: member.nickname }), title: t("member_actions_for", { name: member.nickname }), className: `flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-gray-600 hover:bg-gray-5 aria-expanded:bg-gray-25 aria-expanded:text-gray-900 ${FOCUS_RING_CLASS}`, children: _jsx(Icon, { icon: "more-horizontal-b", size: 18 }) }) }))] }, member.userID));
43
43
  };
44
44
  const renderList = (list) => (_jsx("ul", { className: "m-0 flex list-none flex-col gap-0.5 p-0", children: list.map(renderRow) }));
45
45
  const renderBody = () => {
@@ -1,6 +1,8 @@
1
1
  export interface MemberDisplayItem {
2
2
  userID: string;
3
3
  nickname: string;
4
+ /** Tells apart members with the same name; missing until user info loads. */
5
+ username?: string;
4
6
  faceURL?: string;
5
7
  isCustomer: boolean;
6
8
  isCurrentUser: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"groupMemberTypes.d.ts","sourceRoot":"","sources":["../../../src/components/message/groupMemberTypes.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB"}
1
+ {"version":3,"file":"groupMemberTypes.d.ts","sourceRoot":"","sources":["../../../src/components/message/groupMemberTypes.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB"}
@@ -1,3 +1,5 @@
1
1
  /** Username from the user's public info `ex`; undefined until known. */
2
2
  export declare const useUserUsername: (userId?: string) => string | undefined;
3
+ /** Usernames for a list of users, fetched in one call; an entry is missing until known. */
4
+ export declare const useUsersUsernames: (userIds: string[]) => Record<string, string>;
3
5
  //# sourceMappingURL=useUserUsername.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useUserUsername.d.ts","sourceRoot":"","sources":["../../../src/hooks/user/useUserUsername.ts"],"names":[],"mappings":"AA+BA,wEAAwE;AACxE,eAAO,MAAM,eAAe,GAAI,SAAS,MAAM,KAAG,MAAM,GAAG,SAoB1D,CAAC"}
1
+ {"version":3,"file":"useUserUsername.d.ts","sourceRoot":"","sources":["../../../src/hooks/user/useUserUsername.ts"],"names":[],"mappings":"AAwCA,wEAAwE;AACxE,eAAO,MAAM,eAAe,GAAI,SAAS,MAAM,KAAG,MAAM,GAAG,SAe1D,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB,GAAI,SAAS,MAAM,EAAE,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAoC1E,CAAC"}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { useEffect } from "react";
2
+ import { useEffect, useMemo } from "react";
3
3
  import { DChatSDK } from "../../constants/sdk";
4
4
  import { useChatContext } from "../../context/ChatContext";
5
5
  import useUsersInfoStore from "../../store/usersInfo";
@@ -26,9 +26,18 @@ const loadUserInfo = (userId, attempt = 0) => {
26
26
  setTimeout(() => loadUserInfo(userId, attempt + 1), delay);
27
27
  });
28
28
  };
29
+ const readUsername = (ex) => {
30
+ var _a, _b, _c;
31
+ try {
32
+ const info = JSON.parse(ex || "{}");
33
+ return ((_c = (_b = (_a = info === null || info === void 0 ? void 0 : info.userInfo) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.username) === null || _c === void 0 ? void 0 : _c.trim()) || undefined;
34
+ }
35
+ catch (_d) {
36
+ return undefined;
37
+ }
38
+ };
29
39
  /** Username from the user's public info `ex`; undefined until known. */
30
40
  export const useUserUsername = (userId) => {
31
- var _a, _b, _c;
32
41
  const { connectStatus } = useChatContext();
33
42
  const user = useUsersInfoStore((state) => userId ? state.usersInfo[userId] : undefined);
34
43
  useEffect(() => {
@@ -39,11 +48,42 @@ export const useUserUsername = (userId) => {
39
48
  pendingUserIds.add(userId);
40
49
  loadUserInfo(userId);
41
50
  }, [userId, user, connectStatus]);
42
- try {
43
- const ex = JSON.parse((user === null || user === void 0 ? void 0 : user.ex) || "{}");
44
- return ((_c = (_b = (_a = ex === null || ex === void 0 ? void 0 : ex.userInfo) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.username) === null || _c === void 0 ? void 0 : _c.trim()) || undefined;
45
- }
46
- catch (_d) {
47
- return undefined;
48
- }
51
+ return readUsername(user === null || user === void 0 ? void 0 : user.ex);
52
+ };
53
+ /** Usernames for a list of users, fetched in one call; an entry is missing until known. */
54
+ export const useUsersUsernames = (userIds) => {
55
+ const { connectStatus } = useChatContext();
56
+ const usersInfo = useUsersInfoStore((state) => state.usersInfo);
57
+ const idsKey = userIds.join(",");
58
+ useEffect(() => {
59
+ if (connectStatus !== ConnectStatus.Connected)
60
+ return;
61
+ const { usersInfo: known } = useUsersInfoStore.getState();
62
+ const missing = Array.from(new Set(userIds)).filter((id) => id && !known[id] && !pendingUserIds.has(id));
63
+ if (!missing.length)
64
+ return;
65
+ missing.forEach((id) => pendingUserIds.add(id));
66
+ // Ids the server doesn't return stay pending, so they aren't asked for again.
67
+ DChatSDK.getUsersInfo(missing)
68
+ .then(({ data }) => {
69
+ useUsersInfoStore.getState().upsertUsers(data !== null && data !== void 0 ? data : []);
70
+ (data !== null && data !== void 0 ? data : []).forEach((user) => pendingUserIds.delete(user.userID));
71
+ })
72
+ .catch((error) => {
73
+ missing.forEach((id) => pendingUserIds.delete(id));
74
+ console.error("Error fetching users info:", error);
75
+ });
76
+ // eslint-disable-next-line react-hooks/exhaustive-deps
77
+ }, [idsKey, connectStatus]);
78
+ return useMemo(() => {
79
+ const usernames = {};
80
+ userIds.forEach((id) => {
81
+ var _a;
82
+ const username = readUsername((_a = usersInfo[id]) === null || _a === void 0 ? void 0 : _a.ex);
83
+ if (username)
84
+ usernames[id] = username;
85
+ });
86
+ return usernames;
87
+ // eslint-disable-next-line react-hooks/exhaustive-deps
88
+ }, [idsKey, usersInfo]);
49
89
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@droppii-org/chat-sdk",
3
- "version": "0.7.22",
3
+ "version": "0.8.0",
4
4
  "description": "Droppii React Chat SDK",
5
5
  "repository": {
6
6
  "type": "git",