@droppii-org/chat-sdk 0.3.0 → 0.3.2

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.
Files changed (74) hide show
  1. package/dist/components/conversation/ConversationByGroupItem.d.ts.map +1 -1
  2. package/dist/components/conversation/ConversationByGroupItem.js +2 -3
  3. package/dist/components/conversation/ConversationBySessionItem.d.ts.map +1 -1
  4. package/dist/components/conversation/ConversationBySessionItem.js +3 -1
  5. package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
  6. package/dist/components/conversation/DeskConversationList.js +1 -1
  7. package/dist/components/conversation-detail/PinnedMessagesPanel.d.ts.map +1 -1
  8. package/dist/components/conversation-detail/PinnedMessagesPanel.js +1 -1
  9. package/dist/components/conversation-detail/ThreadProfilePanel.d.ts.map +1 -1
  10. package/dist/components/conversation-detail/ThreadProfilePanel.js +1 -1
  11. package/dist/components/conversation-detail/bot/BotMenuSheet.d.ts.map +1 -1
  12. package/dist/components/conversation-detail/bot/BotMenuSheet.js +1 -1
  13. package/dist/components/group/AddMemberModal.d.ts.map +1 -1
  14. package/dist/components/group/AddMemberModal.js +1 -1
  15. package/dist/components/group/AdminPermissionModal.d.ts +7 -1
  16. package/dist/components/group/AdminPermissionModal.d.ts.map +1 -1
  17. package/dist/components/group/AdminPermissionModal.js +88 -33
  18. package/dist/components/group/CreateGroupForm.d.ts.map +1 -1
  19. package/dist/components/group/CreateGroupForm.js +44 -10
  20. package/dist/components/group/GroupCompositeAvatar.d.ts +11 -0
  21. package/dist/components/group/GroupCompositeAvatar.d.ts.map +1 -0
  22. package/dist/components/group/GroupCompositeAvatar.js +52 -0
  23. package/dist/components/media-collection/index.d.ts.map +1 -1
  24. package/dist/components/media-collection/index.js +3 -3
  25. package/dist/components/media-resources/MediaResourcePanel.d.ts.map +1 -1
  26. package/dist/components/media-resources/MediaResourcePanel.js +1 -1
  27. package/dist/components/message/GroupMembersDrawer.d.ts.map +1 -1
  28. package/dist/components/message/GroupMembersDrawer.js +57 -29
  29. package/dist/components/message/MessageHeader.d.ts.map +1 -1
  30. package/dist/components/message/MessageHeader.js +17 -5
  31. package/dist/components/message/item/GroupNotificationMessage.d.ts +7 -0
  32. package/dist/components/message/item/GroupNotificationMessage.d.ts.map +1 -0
  33. package/dist/components/message/item/GroupNotificationMessage.js +13 -0
  34. package/dist/components/message/item/index.d.ts.map +1 -1
  35. package/dist/components/message/item/index.js +10 -2
  36. package/dist/components/message/item/renderMessageContent.d.ts.map +1 -1
  37. package/dist/components/message/item/renderMessageContent.js +18 -0
  38. package/dist/components/search-conversation/SearchDrawer.d.ts.map +1 -1
  39. package/dist/components/search-conversation/SearchDrawer.js +1 -1
  40. package/dist/components/thread/GroupThreadInfo.d.ts.map +1 -1
  41. package/dist/components/thread/GroupThreadInfo.js +36 -5
  42. package/dist/components/thread/SingleThreadInfo.d.ts.map +1 -1
  43. package/dist/components/thread/SingleThreadInfo.js +1 -1
  44. package/dist/components/thread/ThreadInfo.d.ts.map +1 -1
  45. package/dist/components/thread/ThreadInfo.js +2 -1
  46. package/dist/components/video-player/VideoPlayerModal.d.ts.map +1 -1
  47. package/dist/components/video-player/VideoPlayerModal.js +1 -1
  48. package/dist/hooks/common/useUploadFile.d.ts +3 -0
  49. package/dist/hooks/common/useUploadFile.d.ts.map +1 -0
  50. package/dist/hooks/common/useUploadFile.js +15 -0
  51. package/dist/hooks/group/useCreateGroup.d.ts.map +1 -1
  52. package/dist/hooks/group/useCreateGroup.js +4 -2
  53. package/dist/hooks/group/useGroupMembers.d.ts +3 -1
  54. package/dist/hooks/group/useGroupMembers.d.ts.map +1 -1
  55. package/dist/hooks/group/useGroupMembers.js +9 -0
  56. package/dist/hooks/message/useMessage.d.ts.map +1 -1
  57. package/dist/hooks/message/useMessage.js +2 -1
  58. package/dist/locales/vi/common.json +1 -0
  59. package/dist/locales/vi/conversation-inbox.json +4 -2
  60. package/dist/services/routes.d.ts +3 -0
  61. package/dist/services/routes.d.ts.map +1 -1
  62. package/dist/services/routes.js +3 -0
  63. package/dist/store/conversation.d.ts.map +1 -1
  64. package/dist/store/conversation.js +10 -0
  65. package/dist/store/session.d.ts +13 -1
  66. package/dist/store/session.d.ts.map +1 -1
  67. package/dist/store/session.js +6 -2
  68. package/dist/styles/global.css +1 -1
  69. package/dist/types/dto.d.ts +11 -0
  70. package/dist/types/dto.d.ts.map +1 -1
  71. package/dist/utils/imCommon.d.ts +4 -0
  72. package/dist/utils/imCommon.d.ts.map +1 -1
  73. package/dist/utils/imCommon.js +16 -0
  74. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { GroupMemberRole } from "@droppii-org/wasm-client-sdk";
3
3
  import { Avatar, Button, Drawer, Dropdown, Empty, Input, message, Modal, Spin } from "antd";
4
4
  import { useEffect, useMemo, useState } from "react";
@@ -16,6 +16,7 @@ import { useKickGroupMember, useSetGroupMemberPermissions, useSetGroupMemberRole
16
16
  import { Icon } from "../../components/icon";
17
17
  import AddMemberModal from "../../components/group/AddMemberModal";
18
18
  import AdminPermissionModal from "../../components/group/AdminPermissionModal";
19
+ import { isGroupConversation } from "../../utils/imCommon";
19
20
  const getMemberDisplayName = (member) => {
20
21
  return member.nickname || member.userID || "";
21
22
  };
@@ -37,13 +38,20 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
37
38
  const [isOpen, setIsOpen] = useState(false);
38
39
  const [showLeaveConfirm, setShowLeaveConfirm] = useState(false);
39
40
  const [showAddMember, setShowAddMember] = useState(false);
40
- const [showAdminPermission, setShowAdminPermission] = useState(false);
41
+ const [adminPermissionMember, setAdminPermissionMember] = useState(null);
41
42
  const [confirmMemberAction, setConfirmMemberAction] = useState(null);
42
43
  const [search, setSearch] = useState("");
43
44
  const debouncedSearch = useDebounce(search, { wait: 300 });
44
45
  const authUserID = useAuthStore((state) => state.userID);
45
46
  const conversationData = useConversationStore((state) => state.conversationData);
46
- const { members, isLoading, error, refetch } = useGroupMembers(groupID);
47
+ // Admin-management actions (assign/remove admin, transfer owner, kick,
48
+ // configure permissions) only make sense for a real group (peerType
49
+ // GROUP) — for a CX thread that merely uses a Group/WorkingGroup session
50
+ // under the hood, roleLevel/permissions reflect a technical role with no
51
+ // relation to who may manage "members", so those actions are hidden
52
+ // entirely rather than shown disabled.
53
+ const isRealGroup = isGroupConversation(conversationData !== null && conversationData !== void 0 ? conversationData : undefined);
54
+ const { members, isLoading, error, refetch, patchMemberRole, patchMemberPermissions } = useGroupMembers(groupID);
47
55
  const { results: searchResults, isSearching } = useSearchGroupMembers(groupID, debouncedSearch);
48
56
  const { mutateAsync: leaveConversation, isPending: isLeaving } = useLeaveConversation();
49
57
  const permissions = useGroupPermission(groupID);
@@ -79,14 +87,20 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
79
87
  isAdmin: member.roleLevel === GroupMemberRole.Admin,
80
88
  permissions,
81
89
  isSendMessageDisabled: !permissions.includes(GROUP_PERMISSION_KEY.sendMessage),
82
- // Mockup only shows a role label under the owner/creator row —
83
- // Admin/Member rows show name only.
84
- roleLabel: isOwner
90
+ // Owner and Admin rows show a role label; plain Member rows show
91
+ // name only.
92
+ roleLabel: isOwner || member.roleLevel === GroupMemberRole.Admin
85
93
  ? getMemberRoleLabel({ member, customerUserID, t })
86
94
  : "",
87
95
  };
88
96
  })
89
97
  .sort((memberA, memberB) => {
98
+ // Group by role first (Owner > Admin > Member), then within each
99
+ // role group put "me" first, then the group owner, then by name.
100
+ const roleRank = (member) => member.isOwner ? 0 : member.isAdmin ? 1 : 2;
101
+ const rankDiff = roleRank(memberA) - roleRank(memberB);
102
+ if (rankDiff !== 0)
103
+ return rankDiff;
90
104
  if (memberA.isCurrentUser !== memberB.isCurrentUser) {
91
105
  return memberA.isCurrentUser ? -1 : 1;
92
106
  }
@@ -163,16 +177,22 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
163
177
  var _a, _b;
164
178
  if (!groupID)
165
179
  return;
180
+ const nextRoleLevel = member.isAdmin
181
+ ? GroupMemberRole.Normal
182
+ : GroupMemberRole.Admin;
166
183
  try {
167
184
  await setMemberRole({
168
185
  groupID,
169
186
  userID: member.userID,
170
- roleLevel: member.isAdmin ? GroupMemberRole.Normal : GroupMemberRole.Admin,
187
+ roleLevel: nextRoleLevel,
171
188
  });
172
189
  message.success(member.isAdmin
173
190
  ? t("remove_from_admin_success")
174
191
  : t("assign_as_admin_success"));
175
- void refetch();
192
+ // Patch the role in place instead of refetching the whole list — a
193
+ // full refetch replaces every member's object identity and re-sorts,
194
+ // which visibly re-renders/reorders rows that didn't actually change.
195
+ patchMemberRole(member.userID, nextRoleLevel);
176
196
  }
177
197
  catch (error) {
178
198
  message.error(((_b = (_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) || t("update_group_info_failed"));
@@ -229,22 +249,25 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
229
249
  return (_jsx("div", { className: "flex flex-col", children: sortedMembers.map((member) => {
230
250
  // Send message / Remove and block are not wired yet (no confirmed
231
251
  // SDK flow for member-scoped block) — kept disabled per scope.
252
+ const leaveGroupItem = {
253
+ key: "leave-group",
254
+ label: t("leave_group"),
255
+ icon: _jsx(Icon, { icon: "logout-b", size: 16 }),
256
+ onClick: handleLeaveGroup,
257
+ danger: true,
258
+ };
232
259
  const menuItems = member.isCurrentUser
233
- ? [
234
- {
235
- key: "mute",
236
- label: t("mute_member"),
237
- icon: _jsx(Icon, { icon: "bell-off-b", size: 16 }),
238
- disabled: true,
239
- },
240
- {
241
- key: "leave-group",
242
- label: t("leave_group"),
243
- icon: _jsx(Icon, { icon: "logout-b", size: 16 }),
244
- onClick: handleLeaveGroup,
245
- danger: true,
246
- },
247
- ]
260
+ ? isRealGroup
261
+ ? [
262
+ {
263
+ key: "mute",
264
+ label: t("mute_member"),
265
+ icon: _jsx(Icon, { icon: "bell-off-b", size: 16 }),
266
+ disabled: true,
267
+ },
268
+ leaveGroupItem,
269
+ ]
270
+ : [leaveGroupItem]
248
271
  : [
249
272
  {
250
273
  key: "send-message",
@@ -275,7 +298,7 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
275
298
  label: t("admin_permission_settings"),
276
299
  icon: _jsx(Icon, { icon: "shield-o", size: 16 }),
277
300
  disabled: !permissions.transferOwnership,
278
- onClick: () => setShowAdminPermission(true),
301
+ onClick: () => setAdminPermissionMember(member),
279
302
  },
280
303
  {
281
304
  key: "remove-admin",
@@ -310,18 +333,23 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
310
333
  disabled: true,
311
334
  },
312
335
  ];
313
- 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 }))] }), _jsx(Dropdown, { menu: { items: menuItems }, trigger: ["click"], placement: "bottomRight", children: _jsx("button", { type: "button", 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));
336
+ 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", 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));
314
337
  }) }));
315
338
  };
316
- return (_jsxs(_Fragment, { children: [_jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: handleOpenDrawer, disabled: disabled || !groupID, children: _jsx(Icon, { icon: "user-two-check-b", size: 22 }) }), _jsx(Drawer, { open: isOpen, onClose: handleCloseDrawer, mask: false, closeIcon: false, styles: {
339
+ return (_jsxs("div", { className: "inline-flex shrink-0", children: [_jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: handleOpenDrawer, disabled: disabled || !groupID, children: _jsx(Icon, { icon: "user-two-check-b", size: 22 }) }), _jsx(Drawer, { open: isOpen, onClose: handleCloseDrawer, mask: false, closeIcon: false, styles: {
317
340
  body: {
318
341
  padding: 0,
319
342
  height: "100%",
320
343
  },
321
- }, getContainer: false, width: 360, children: _jsxs("div", { className: "flex flex-col h-full bg-white", children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-4 border-b border-gray-100", children: [_jsx("span", { className: "text-lg font-medium", children: t("members") }), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: handleCloseDrawer, children: _jsx(Icon, { icon: "close-b", size: 22 }) })] }), _jsxs("div", { className: "flex items-center gap-2 px-4 py-3", children: [_jsx(Input, { value: search, onChange: (event) => setSearch(event.target.value), placeholder: t("search_member_placeholder"), prefix: _jsx(Icon, { icon: "search-o", size: 16, className: "text-gray-400" }), className: "h-10" }), canAddMember && (_jsx(Button, { type: "primary", shape: "default", className: "w-10 h-10 p-0 shrink-0 flex items-center justify-center rounded-lg", onClick: () => setShowAddMember(true), children: _jsx(Icon, { icon: "user-add-b", size: 18 }) }))] }), _jsx("div", { className: "flex-1 overflow-y-auto", children: renderContent() })] }) }), _jsx(Modal, { centered: true, open: showLeaveConfirm, onOk: handleConfirmLeave, onCancel: () => setShowLeaveConfirm(false), title: t("leave_group_confirm_title"), okText: t("leave_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isLeaving, getContainer: false, children: _jsx("p", { children: t("leave_group_confirm_message") }) }), _jsx(Modal, { centered: true, open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "remove", onOk: handleConfirmRemoveMember, onCancel: () => setConfirmMemberAction(null), title: t("remove_member_confirm_title"), okText: t("remove_from_group"), cancelText: t("cancel"), okType: "danger", getContainer: false, children: _jsx("p", { children: t("remove_member_confirm_message", {
344
+ }, getContainer: false, forceRender: true, width: 360, children: _jsxs("div", { className: "flex flex-col h-full bg-white", children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-4 border-b border-gray-100", children: [_jsx("span", { className: "text-lg font-medium", children: t("members") }), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: handleCloseDrawer, children: _jsx(Icon, { icon: "close-b", size: 22 }) })] }), _jsxs("div", { className: "flex items-center gap-2 px-4 py-3", children: [_jsx(Input, { value: search, onChange: (event) => setSearch(event.target.value), placeholder: t("search_member_placeholder"), prefix: _jsx(Icon, { icon: "search-o", size: 16, className: "text-gray-400" }), className: "h-10" }), canAddMember && (_jsx(Button, { type: "primary", shape: "default", className: "w-10 h-10 p-0 shrink-0 flex items-center justify-center rounded-lg", onClick: () => setShowAddMember(true), children: _jsx(Icon, { icon: "user-add-b", size: 18 }) }))] }), _jsx("div", { className: "flex-1 overflow-y-auto", children: renderContent() })] }) }), groupID && (_jsx(AddMemberModal, { open: showAddMember, groupID: groupID, onClose: () => setShowAddMember(false) })), groupID && (_jsx(AdminPermissionModal, { open: Boolean(adminPermissionMember), groupID: groupID, onClose: () => setAdminPermissionMember(null), member: adminPermissionMember
345
+ ? {
346
+ userID: adminPermissionMember.userID,
347
+ permissions: adminPermissionMember.permissions,
348
+ }
349
+ : undefined, onMemberPermissionsSaved: patchMemberPermissions })), _jsx(Modal, { centered: true, open: showLeaveConfirm, onOk: handleConfirmLeave, onCancel: () => setShowLeaveConfirm(false), title: t("leave_group_confirm_title"), okText: t("leave_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isLeaving, getContainer: false, forceRender: true, children: _jsx("p", { children: t("leave_group_confirm_message") }) }), _jsx(Modal, { centered: true, open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "remove", onOk: handleConfirmRemoveMember, onCancel: () => setConfirmMemberAction(null), title: t("remove_member_confirm_title"), okText: t("remove_from_group"), cancelText: t("cancel"), okType: "danger", getContainer: false, forceRender: true, children: _jsx("p", { children: t("remove_member_confirm_message", {
322
350
  name: confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.member.nickname,
323
- }) }) }), _jsx(Modal, { centered: true, open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "transfer-owner", onOk: handleConfirmTransferOwner, onCancel: () => setConfirmMemberAction(null), title: t("transfer_owner_confirm_title"), okText: t("transfer_owner"), cancelText: t("cancel"), okType: "danger", getContainer: false, children: _jsx("p", { children: t("transfer_owner_confirm_message", {
351
+ }) }) }), _jsx(Modal, { centered: true, open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "transfer-owner", onOk: handleConfirmTransferOwner, onCancel: () => setConfirmMemberAction(null), title: t("transfer_owner_confirm_title"), okText: t("transfer_owner"), cancelText: t("cancel"), okType: "danger", getContainer: false, forceRender: true, children: _jsx("p", { children: t("transfer_owner_confirm_message", {
324
352
  name: confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.member.nickname,
325
- }) }) }), groupID && (_jsx(AddMemberModal, { open: showAddMember, groupID: groupID, onClose: () => setShowAddMember(false) })), groupID && (_jsx(AdminPermissionModal, { open: showAdminPermission, groupID: groupID, onClose: () => setShowAdminPermission(false) }))] }));
353
+ }) }) })] }));
326
354
  };
327
355
  export default GroupMembersDrawer;
@@ -1 +1 @@
1
- {"version":3,"file":"MessageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageHeader.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAGzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAO/C,UAAU,kBAAkB;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,KAAK,sBAAsB,GAAG,aAAa,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,sBAAsB,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,QAAA,MAAM,aAAa,GAAI,0DAKpB,kBAAkB,4CAkNpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"MessageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageHeader.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAGzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAQ/C,UAAU,kBAAkB;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,KAAK,sBAAsB,GAAG,aAAa,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,sBAAsB,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,QAAA,MAAM,aAAa,GAAI,0DAKpB,kBAAkB,4CAyOpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -12,8 +12,9 @@ import SelectSession from "./SelectSession";
12
12
  import { useUpdateSession } from "../../hooks/session/useUpdateSession";
13
13
  import useAuthStore from "../../store/auth";
14
14
  import SearchDrawer from "../../components/search-conversation/SearchDrawer";
15
- import { isGroupSession } from "../../utils/imCommon";
15
+ import { isGroupSession, isGroupConversation } from "../../utils/imCommon";
16
16
  import { useGroupPermission } from "../../hooks/group/useGroupPermission";
17
+ import GroupCompositeAvatar from "../../components/group/GroupCompositeAvatar";
17
18
  import GroupMembersDrawer from "./GroupMembersDrawer";
18
19
  const MessageHeader = ({ onClose, currentSession, isJoined, onOpenThreadInfo, }) => {
19
20
  var _a, _b;
@@ -26,6 +27,20 @@ const MessageHeader = ({ onClose, currentSession, isJoined, onOpenThreadInfo, })
26
27
  const permissions = useGroupPermission(conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID);
27
28
  const { avatar, displayName } = useConversationDisplayData(conversationData);
28
29
  const shouldShowMemberCount = isGroupSession(conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationType);
30
+ // A "real" group (peerType GROUP) vs a CX support thread that happens to
31
+ // use a Group/WorkingGroup session under the hood (e.g. a multi-agent
32
+ // support conversation with several members) — only the former hides
33
+ // tag/status/Phiên hỗ trợ. permissions.viewMemberInformation (derived
34
+ // from the current user's own roleLevel in that Group/WorkingGroup
35
+ // session) is likewise only meaningful for a real group — for a CX
36
+ // thread it reflects a technical role that has nothing to do with who
37
+ // may view the member list, so it's bypassed there. The member list
38
+ // button itself still shows for both (shouldShowMemberCount).
39
+ const isRealGroup = isGroupConversation(conversationData !== null && conversationData !== void 0 ? conversationData : undefined);
40
+ const canViewMemberList = shouldShowMemberCount &&
41
+ isJoined === true &&
42
+ isCrm &&
43
+ (!isRealGroup || permissions.viewMemberInformation);
29
44
  const [currentSessionStatus, setCurrentSessionStatus] = useState(SessionStatus.UNASSIGNED);
30
45
  const [currentSessionTag, setCurrentSessionTag] = useState(SessionTag.NONE);
31
46
  const statusOptions = useMemo(() => {
@@ -129,9 +144,6 @@ const MessageHeader = ({ onClose, currentSession, isJoined, onOpenThreadInfo, })
129
144
  setCurrentSessionStatus(currentSession.status);
130
145
  }
131
146
  }, [currentSession]);
132
- return (_jsxs("div", { className: "px-4 py-3 flex items-center border-b gap-3 bg-white flex-wrap", children: [_jsx(Avatar, { src: avatar, size: "large", className: "min-w-10 min-h-10", children: ((_a = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _a === void 0 ? void 0 : _a.call(displayName, 0)) || "A" }), _jsxs("div", { className: "flex flex-col overflow-hidden flex-1", children: [_jsx("p", { className: "text-base truncate", children: displayName || "" }), shouldShowMemberCount && (_jsx("p", { className: "text-xs text-gray-500 truncate", children: t("member_count", { count: (_b = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.memberCount) !== null && _b !== void 0 ? _b : 0 }) }))] }), _jsxs("div", { className: "flex items-center gap-2 justify-end overflow-hidden", children: [isCx && (_jsx(SelectSession, { placeholder: t("select_tag"), options: tagOptions, value: currentSessionTag, onChange: (value) => handleUpdateSession(value, "tag", value === currentSessionTag), excludeOptions: [SessionTag.SLOW_PROCESSING, SessionTag.NONE] })), isCx && (_jsx(SelectSession, { placeholder: t("select_status"), options: statusOptions, value: currentSessionStatus, onChange: (value) => handleUpdateSession(value, "status", value === currentSessionStatus) })), _jsx(SearchDrawer, {}), shouldShowMemberCount &&
133
- isJoined === true &&
134
- isCrm &&
135
- permissions.viewMemberInformation && (_jsx(GroupMembersDrawer, { groupID: conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID, conversationId: conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID, currentSession: currentSession })), _jsx(MediaCollection, {}), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: onOpenThreadInfo, children: _jsx(Icon, { icon: "align-justify-o", size: 22 }) }), !!onClose && (_jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: onClose, children: _jsx(Icon, { icon: "close-b", size: 22 }) }))] })] }));
147
+ return (_jsxs("div", { className: "px-4 py-3 flex items-center border-b gap-3 bg-white flex-wrap", children: [shouldShowMemberCount ? (_jsx(GroupCompositeAvatar, { groupID: conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID, faceURL: avatar, ownerUserID: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.ownerUserID, groupName: displayName, size: 40, className: "min-w-10 min-h-10" })) : (_jsx(Avatar, { src: avatar, size: "large", className: "min-w-10 min-h-10", children: ((_a = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _a === void 0 ? void 0 : _a.call(displayName, 0)) || "A" })), _jsxs("div", { className: "flex flex-col overflow-hidden flex-1", children: [_jsx("p", { className: "text-base truncate", children: displayName || "" }), shouldShowMemberCount && (_jsx("p", { className: "text-xs text-gray-500 truncate", children: t("member_count", { count: (_b = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.memberCount) !== null && _b !== void 0 ? _b : 0 }) }))] }), _jsxs("div", { className: "flex items-center gap-2 justify-end overflow-hidden", children: [isCx && !isRealGroup && (_jsx(SelectSession, { placeholder: t("select_tag"), options: tagOptions, value: currentSessionTag, onChange: (value) => handleUpdateSession(value, "tag", value === currentSessionTag), excludeOptions: [SessionTag.SLOW_PROCESSING, SessionTag.NONE] })), isCx && !isRealGroup && (_jsx(SelectSession, { placeholder: t("select_status"), options: statusOptions, value: currentSessionStatus, onChange: (value) => handleUpdateSession(value, "status", value === currentSessionStatus) })), _jsx(SearchDrawer, {}), canViewMemberList && (_jsx(GroupMembersDrawer, { groupID: conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID, conversationId: conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID, currentSession: currentSession })), _jsx(MediaCollection, {}), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: onOpenThreadInfo, children: _jsx(Icon, { icon: "align-justify-o", size: 22 }) }), !!onClose && (_jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: onClose, children: _jsx(Icon, { icon: "close-b", size: 22 }) }))] })] }));
136
148
  };
137
149
  export default MessageHeader;
@@ -0,0 +1,7 @@
1
+ import { MessageItem } from "@droppii-org/wasm-client-sdk";
2
+ interface GroupNotificationMessageItemProps {
3
+ message: MessageItem;
4
+ }
5
+ declare const GroupNotificationMessageItem: ({ message }: GroupNotificationMessageItemProps) => import("react/jsx-runtime").JSX.Element | null;
6
+ export default GroupNotificationMessageItem;
7
+ //# sourceMappingURL=GroupNotificationMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GroupNotificationMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/GroupNotificationMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAI3D,UAAU,iCAAiC;IACzC,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,QAAA,MAAM,4BAA4B,GAAI,aAAa,iCAAiC,mDAiBnF,CAAC;AAEF,eAAe,4BAA4B,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useTranslation } from "react-i18next";
4
+ import { getGroupNotificationText } from "../../../utils/messageLog";
5
+ const GroupNotificationMessageItem = ({ message }) => {
6
+ var _a;
7
+ const { t } = useTranslation();
8
+ const text = getGroupNotificationText(message.contentType, (_a = message.notificationElem) === null || _a === void 0 ? void 0 : _a.detail, t);
9
+ if (!text)
10
+ return null;
11
+ return (_jsx("div", { className: "flex justify-center", children: _jsx("span", { className: "rounded-full bg-gray-200 px-3 py-1.5 text-center text-[13px] font-normal text-gray-900", children: text }) }));
12
+ };
13
+ export default GroupNotificationMessageItem;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,IAAI,eAAe,EAG/B,MAAM,8BAA8B,CAAC;AAiCtC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAClD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAoBD,QAAA,MAAM,WAAW,GAAI,qMAalB,gBAAgB,mDAmRlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,IAAI,eAAe,EAG/B,MAAM,8BAA8B,CAAC;AAkCtC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAClD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAoBD,QAAA,MAAM,WAAW,GAAI,qMAalB,gBAAgB,mDA8RlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -18,7 +18,8 @@ import MessageStatusIndicator from "./MessageStatusIndicator";
18
18
  import { useSendMessage, isMediaResendable, } from "../../../hooks/message/useSendMessage";
19
19
  import { Icon } from "../../../components/icon";
20
20
  import SystemLogMessageItem from "./SystemLogMessage";
21
- import { isSystemLogMessageType } from "../../../utils/messageLog";
21
+ import GroupNotificationMessageItem from "./GroupNotificationMessage";
22
+ import { isGroupNotificationMessageType, isSystemLogMessageType } from "../../../utils/messageLog";
22
23
  import { buildMessageToolboxMenuItems, getCopyableMessageText, isCopyableMessageType, isPinnableMessageType, MessageToolboxActionKey, MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, useMessageToolboxVisibility, } from "../../../components/message/toolbox";
23
24
  const MESSAGE_AVATAR_SIZE = 24;
24
25
  const MessageAvatar = ({ avatarUrl, senderNickname, }) => {
@@ -35,7 +36,8 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
35
36
  const { isDeliveredForUi, isRevocable, isMine } = useMessageToolboxVisibility(message, userID);
36
37
  const contextMenuItems = useMemo(() => {
37
38
  if ((message === null || message === void 0 ? void 0 : message.contentType) === MessageType.RevokeMessage ||
38
- isSystemLogMessageType(message === null || message === void 0 ? void 0 : message.contentType)) {
39
+ isSystemLogMessageType(message === null || message === void 0 ? void 0 : message.contentType) ||
40
+ isGroupNotificationMessageType(message === null || message === void 0 ? void 0 : message.contentType)) {
39
41
  return [];
40
42
  }
41
43
  const closeToolbox = () => onContextMenuOpenChange === null || onContextMenuOpenChange === void 0 ? void 0 : onContextMenuOpenChange(false);
@@ -118,6 +120,7 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
118
120
  }, [conversationData === null || conversationData === void 0 ? void 0 : conversationData.ex, isCrm, message === null || message === void 0 ? void 0 : message.sendID, userID]);
119
121
  const isInternalMessage = Boolean(message === null || message === void 0 ? void 0 : message.isInternal);
120
122
  const isSystemLogMessage = isSystemLogMessageType(message === null || message === void 0 ? void 0 : message.contentType);
123
+ const isGroupNotificationMessage = isGroupNotificationMessageType(message === null || message === void 0 ? void 0 : message.contentType);
121
124
  const isStickerMessage = (message === null || message === void 0 ? void 0 : message.contentType) === MessageType.StickerMessage;
122
125
  const hasContextMenu = contextMenuItems.length > 0;
123
126
  const isLatestMine = ((_a = allMessages.find((m) => m.sendID === userID)) === null || _a === void 0 ? void 0 : _a.clientMsgID) ===
@@ -145,6 +148,11 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
145
148
  timeBreakNode,
146
149
  _jsx(SystemLogMessageItem, { message: message })));
147
150
  }
151
+ if (isGroupNotificationMessage) {
152
+ return (_createElement("div", Object.assign({}, messageContainerProps, { key: message === null || message === void 0 ? void 0 : message.clientMsgID }),
153
+ timeBreakNode,
154
+ _jsx(GroupNotificationMessageItem, { message: message })));
155
+ }
148
156
  const bubbleNode = (_jsx(MessageBubble, { isMine: isMine, isInternal: isInternalMessage, senderName: message === null || message === void 0 ? void 0 : message.senderNickname, showSenderName: showSenderName, showTip: showTip, id: `${MSG_ITEM_CONTENT_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`, content: renderBubbleContent(message, onPressQuoteMessage), isTransparent: isStickerMessage }));
149
157
  const showPinnedBadge = Boolean(message === null || message === void 0 ? void 0 : message.isPinned) && Boolean(onPinMessage);
150
158
  const pinnedBadgeNode = showPinnedBadge ? (_jsx("span", { "data-testid": "message-pinned-badge", className: clsx("absolute -top-2.5 z-[1] flex h-[22px] w-[26px] items-center justify-center rounded-full border border-white bg-gray-25", isMine ? "left-0" : "right-0"), children: _jsx(Icon, { icon: "thumbtack-b", size: 12, className: "text-primary-400" }) })) : null;
@@ -1 +1 @@
1
- {"version":3,"file":"renderMessageContent.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/renderMessageContent.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,eAAe,EAAe,MAAM,8BAA8B,CAAC;AAa3F,eAAO,MAAM,mBAAmB,GAAI,SAAS,eAAe,4CA2B3D,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,eAAe,EACxB,sBAAsB,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,4CAwBpD,CAAC"}
1
+ {"version":3,"file":"renderMessageContent.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/renderMessageContent.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,eAAe,EAAe,MAAM,8BAA8B,CAAC;AAc3F,eAAO,MAAM,mBAAmB,GAAI,SAAS,eAAe,4CA4C3D,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,eAAe,EACxB,sBAAsB,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,4CAwBpD,CAAC"}
@@ -11,6 +11,7 @@ import QuoteMessageItem from "./QuoteMessage";
11
11
  import SystemLogMessageItem from "./SystemLogMessage";
12
12
  import CustomMessageItem from "./CustomMessage";
13
13
  import StickerMessageItem from "./StickerMessage";
14
+ import GroupNotificationMessageItem from "./GroupNotificationMessage";
14
15
  export const renderMessageByType = (message) => {
15
16
  switch (message === null || message === void 0 ? void 0 : message.contentType) {
16
17
  case MessageType.TextMessage:
@@ -34,6 +35,23 @@ export const renderMessageByType = (message) => {
34
35
  return _jsx(CustomMessageItem, { message: message });
35
36
  case MessageType.StickerMessage:
36
37
  return _jsx(StickerMessageItem, { message: message });
38
+ case MessageType.GroupCreated:
39
+ case MessageType.GroupInfoUpdated:
40
+ case MessageType.MemberQuit:
41
+ case MessageType.GroupOwnerTransferred:
42
+ case MessageType.MemberKicked:
43
+ case MessageType.MemberInvited:
44
+ case MessageType.MemberEnter:
45
+ case MessageType.GroupDismissed:
46
+ case MessageType.GroupMemberMuted:
47
+ case MessageType.GroupMemberCancelMuted:
48
+ case MessageType.GroupMuted:
49
+ case MessageType.GroupCancelMuted:
50
+ case MessageType.GroupAnnouncementUpdated:
51
+ case MessageType.GroupNameUpdated:
52
+ {
53
+ return _jsx(GroupNotificationMessageItem, { message: message });
54
+ }
37
55
  default:
38
56
  return _jsx(TextMessageItem, { message: message });
39
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SearchDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/SearchDrawer.tsx"],"names":[],"mappings":"AAQA,QAAA,MAAM,YAAY,+CAgFjB,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"SearchDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/SearchDrawer.tsx"],"names":[],"mappings":"AAQA,QAAA,MAAM,YAAY,+CAiFjB,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -26,7 +26,7 @@ const SearchDrawer = () => {
26
26
  padding: 0,
27
27
  height: "100%",
28
28
  },
29
- }, getContainer: false, width: isMobile ? "100%" : 360, children: _jsxs("div", { className: "flex flex-col h-full", children: [_jsxs("div", { className: "flex items-center justify-between p-3", children: [_jsx("span", { className: "text-lg font-medium", children: t("search_message_title") }), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: toggle, children: _jsx(Icon, { icon: "close-b", size: 22 }) })] }), _jsx("div", { className: "px-3", children: _jsx(Input, { ref: searchInputRef, placeholder: t("search"), prefix: _jsx(Icon, { icon: "search-o", size: 18, className: "text-gray-400" }), onChange: (e) => {
29
+ }, getContainer: false, forceRender: true, width: isMobile ? "100%" : 360, children: _jsxs("div", { className: "flex flex-col h-full", children: [_jsxs("div", { className: "flex items-center justify-between p-3", children: [_jsx("span", { className: "text-lg font-medium", children: t("search_message_title") }), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: toggle, children: _jsx(Icon, { icon: "close-b", size: 22 }) })] }), _jsx("div", { className: "px-3", children: _jsx(Input, { ref: searchInputRef, placeholder: t("search"), prefix: _jsx(Icon, { icon: "search-o", size: 18, className: "text-gray-400" }), onChange: (e) => {
30
30
  setSearch(e.target.value);
31
31
  }, className: "rounded-lg text-sm", size: "large", allowClear: true, value: search, autoFocus: false }) }), _jsx("div", { className: "flex-1 py-3 overflow-auto", children: _jsx(SearchMessageOnCurrentConversation, { searchTerm: search, onClose: toggle }) })] }) })] }));
32
32
  };
@@ -1 +1 @@
1
- {"version":3,"file":"GroupThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/GroupThreadInfo.tsx"],"names":[],"mappings":"AAgBA,MAAM,WAAW,qBAAqB;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,UAAU,oBAAoB;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC;AAID,QAAA,MAAM,eAAe,GAAI,qBAAqB,oBAAoB,mDAmcjE,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"GroupThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/GroupThreadInfo.tsx"],"names":[],"mappings":"AAmBA,MAAM,WAAW,qBAAqB;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,UAAU,oBAAoB;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC;AAID,QAAA,MAAM,eAAe,GAAI,qBAAqB,oBAAoB,mDA4fjE,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -1,6 +1,6 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useState } from "react";
3
- import { Avatar, Input, Modal, Switch, message } from "antd";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { Input, Modal, Switch, message } from "antd";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import { GroupMemberRole, MessageReceiveOptType } from "@droppii-org/wasm-client-sdk";
6
6
  import { Icon } from "../../components/icon";
@@ -12,10 +12,13 @@ import { useUpdateGroupInfo } from "../../hooks/group/useUpdateGroupInfo";
12
12
  import { useToggleGroupSendMessage } from "../../hooks/group/useToggleGroupSendMessage";
13
13
  import { useDismissGroup } from "../../hooks/group/useDismissGroup";
14
14
  import { useGroupPermission } from "../../hooks/group/useGroupPermission";
15
+ import { useUploadFile } from "../../hooks/common/useUploadFile";
16
+ import { validateFile } from "../../utils/fileValidation";
15
17
  import AdminPermissionModal from "../../components/group/AdminPermissionModal";
16
18
  import MemberPermissionPanel from "../../components/group/MemberPermissionPanel";
19
+ import GroupCompositeAvatar from "../../components/group/GroupCompositeAvatar";
17
20
  const GroupThreadInfo = ({ onClose, config }) => {
18
- var _a, _b, _c, _d, _e;
21
+ var _a, _b, _c;
19
22
  const { t } = useTranslation();
20
23
  const conversationData = useConversationStore((state) => state.conversationData);
21
24
  const currentGroupInfo = useConversationStore((state) => state.currentGroupInfo);
@@ -34,6 +37,7 @@ const GroupThreadInfo = ({ onClose, config }) => {
34
37
  const [confirmAction, setConfirmAction] = useState(null);
35
38
  const [activeRow, setActiveRow] = useState(null);
36
39
  const [notifyEnabled, setNotifyEnabled] = useState((conversationData === null || conversationData === void 0 ? void 0 : conversationData.recvMsgOpt) !== MessageReceiveOptType.NotNotify);
40
+ const avatarInputRef = useRef(null);
37
41
  // Q4 (non-block, pending BE/SDK confirmation): openIM's GroupItem has no
38
42
  // readable "is send disabled" field for changeGroupMute — tracked locally
39
43
  // until BE confirms where (or whether) this persists server-side.
@@ -42,6 +46,7 @@ const GroupThreadInfo = ({ onClose, config }) => {
42
46
  setNotifyEnabled((conversationData === null || conversationData === void 0 ? void 0 : conversationData.recvMsgOpt) !== MessageReceiveOptType.NotNotify);
43
47
  }, [conversationData === null || conversationData === void 0 ? void 0 : conversationData.recvMsgOpt]);
44
48
  const { mutate: updateGroupInfo } = useUpdateGroupInfo();
49
+ const { mutate: uploadFile, isPending: isAvatarUploading } = useUploadFile();
45
50
  const { mutate: toggleSendMessage, isPending: isTogglingSendMessage } = useToggleGroupSendMessage();
46
51
  const { mutate: toggleNotification, isPending: isTogglingNotification } = useToggleConversationNotification();
47
52
  const { mutateAsync: leaveConversation, isPending: isLeaving } = useLeaveConversation();
@@ -76,6 +81,32 @@ const GroupThreadInfo = ({ onClose, config }) => {
76
81
  return;
77
82
  updateGroupInfo({ groupID, introduction: trimmed }, { onError: () => message.error(t("update_group_info_failed")) });
78
83
  };
84
+ const handleAvatarClick = () => {
85
+ var _a;
86
+ if (isAvatarUploading)
87
+ return;
88
+ (_a = avatarInputRef.current) === null || _a === void 0 ? void 0 : _a.click();
89
+ };
90
+ const handleAvatarSelect = (event) => {
91
+ var _a;
92
+ const file = (_a = event.target.files) === null || _a === void 0 ? void 0 : _a[0];
93
+ event.target.value = "";
94
+ if (!file || !groupID)
95
+ return;
96
+ const validation = validateFile(file, t);
97
+ if (!validation.isValid) {
98
+ message.error(validation.error);
99
+ return;
100
+ }
101
+ uploadFile(file, {
102
+ onSuccess: (uploaded) => {
103
+ if (!(uploaded === null || uploaded === void 0 ? void 0 : uploaded.publicUrl))
104
+ return;
105
+ updateGroupInfo({ groupID, faceURL: uploaded.publicUrl }, { onError: () => message.error(t("update_group_info_failed")) });
106
+ },
107
+ onError: () => message.error(t("avatar_upload_failed")),
108
+ });
109
+ };
79
110
  const handleToggleNotification = (checked) => {
80
111
  if (!conversationID)
81
112
  return;
@@ -151,6 +182,6 @@ const GroupThreadInfo = ({ onClose, config }) => {
151
182
  if (!groupID) {
152
183
  return null;
153
184
  }
154
- return (_jsxs("div", { className: "h-full w-[330px] bg-white shadow-md flex flex-col relative overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-4 border-b border-gray-100", children: [_jsx("span", { className: "text-lg font-medium", children: t("thread_info_title") }), _jsx("button", { type: "button", className: "flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:bg-gray-100", onClick: onClose, children: _jsx(Icon, { icon: "close-o", size: 20 }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-4", children: [_jsxs("div", { className: "relative shrink-0", children: [_jsx(Avatar, { src: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.faceURL, size: 56, children: ((_d = (_c = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName) === null || _c === void 0 ? void 0 : _c.charAt) === null || _d === void 0 ? void 0 : _d.call(_c, 0)) || "G" }), permissions.updateGroupAvatar && (_jsx("span", { className: "absolute -bottom-1 -right-1 flex items-center justify-center w-5 h-5 rounded-full bg-black text-white", children: _jsx(Icon, { icon: "camera-o", size: 12 }) }))] }), _jsx("div", { className: "flex-1 min-w-0", children: editingField === "name" ? (_jsx(Input, { autoFocus: true, value: nameValue, onChange: (event) => setNameValue(event.target.value), onPressEnter: saveName, onBlur: saveName, maxLength: 100 })) : (_jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("p", { className: "text-base font-medium truncate", children: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName }), permissions.updateGroupName && (_jsx(Icon, { icon: "edit-o", size: 16, className: "shrink-0 cursor-pointer text-gray-500", onClick: startEditName }))] })) })] }), _jsx("div", { className: "px-4 pb-4", children: editingField === "description" ? (_jsxs("div", { className: "flex flex-col gap-3 bg-[#f5f5f5] rounded-lg p-3", children: [_jsxs("span", { className: "flex items-center gap-2 text-sm font-medium text-gray-900", children: [_jsx(Icon, { icon: "info-circle-o", size: 18, className: "text-gray-500" }), t("description")] }), _jsx(Input.TextArea, { autoFocus: true, value: descriptionValue, onChange: (event) => setDescriptionValue(event.target.value), placeholder: t("enter_group_description"), autoSize: { minRows: 1, maxRows: 4 }, maxLength: 500, className: "bg-white" }), _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx("button", { type: "button", className: "px-4 py-1.5 rounded-full border border-primary-500 text-primary-500 text-sm font-medium", onClick: cancelEditDescription, children: t("cancel") }), _jsx("button", { type: "button", className: "px-4 py-1.5 rounded-full text-primary-500 text-sm font-medium disabled:text-gray-300", disabled: descriptionValue.trim() === ((_e = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) !== null && _e !== void 0 ? _e : ""), onClick: saveDescription, children: t("save") })] })] })) : (_jsxs("div", { className: "flex items-start justify-between gap-2 bg-[#f5f5f5] rounded-lg px-3 py-2.5", children: [_jsxs("div", { className: "flex items-start gap-2 flex-1 min-w-0", children: [_jsx(Icon, { icon: "info-circle-o", size: 18, className: "shrink-0 mt-0.5 text-gray-900" }), _jsxs("div", { className: "flex flex-col gap-0.5 min-w-0", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: t("description") }), _jsx("p", { className: "text-sm text-gray-400 truncate", children: (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) || t("no_description") })] })] }), permissions.updateGroupDescription && (_jsx(Icon, { icon: "edit-o", size: 16, className: "shrink-0 cursor-pointer text-gray-500", onClick: startEditDescription }))] })) }), _jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 rounded-lg overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-o", size: 18 }), t("notification")] }), _jsx(Switch, { checked: notifyEnabled, onChange: handleToggleNotification, loading: isTogglingNotification })] }), (config === null || config === void 0 ? void 0 : config.showAllowSendMessage) && (_jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "user-check-o", size: 18 }), t("allow_send_message")] }), _jsx(Switch, { checked: allowSendMessage, onChange: handleToggleSendMessage, loading: isTogglingSendMessage })] })), isAdminOrOwner && (config === null || config === void 0 ? void 0 : config.showMutedChatList) && (_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("muted-chat-list"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-off-o", size: 18 }), t("muted_chat_list")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })), _jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("block-list"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t("block_list")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })] }), permissions.configGroupPermission && (_jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: [_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("member-permission"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "shield-o", size: 18 }), t("member_permission_settings")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] }), _jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("admin-permission"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "shield-done-o", size: 18 }), t("admin_permission_settings")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })] })), _jsx("div", { className: "mx-4 mt-3 rounded-lg overflow-hidden bg-[#f5f5f5]", children: _jsxs("button", { type: "button", className: "w-full flex items-center gap-3 px-3 py-3 text-left text-sm text-gray-400 cursor-not-allowed", disabled: true, title: t("invite_via_link_pending"), children: [_jsx(Icon, { icon: "link-alt-o", size: 18 }), t("invite_via_link")] }) }), _jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 mb-4 rounded-lg overflow-hidden", children: [_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("delete"), children: [_jsx(Icon, { icon: "trash-o", size: 18 }), t("delete_conversation")] }), _jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("leave"), children: [_jsx(Icon, { icon: "logout-o", size: 18 }), t("leave_group")] }), isAdminOrOwner && (_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("disband"), children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t("disband_group")] }))] })] }), _jsx(Modal, { centered: true, open: confirmAction === "leave", onOk: handleConfirmLeave, onCancel: () => setConfirmAction(null), title: t("leave_group_confirm_title"), okText: t("leave_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isLeaving, getContainer: false, children: _jsx("p", { children: t("leave_group_confirm_message") }) }), _jsx(Modal, { centered: true, open: confirmAction === "disband", onOk: handleConfirmDisband, onCancel: () => setConfirmAction(null), title: t("disband_group_confirm_title"), okText: t("disband_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isDismissing, getContainer: false, children: _jsx("p", { children: t("disband_group_confirm_message") }) }), _jsx(Modal, { centered: true, open: confirmAction === "delete", onOk: handleConfirmDelete, onCancel: () => setConfirmAction(null), title: t("delete_conversation_confirm_title"), okText: t("delete_conversation"), cancelText: t("cancel"), okType: "danger", confirmLoading: isDeleting, getContainer: false, children: _jsx("p", { children: t("delete_conversation_confirm_message") }) }), _jsx(MemberPermissionPanel, { open: activeRow === "member-permission", groupID: groupID, onClose: () => setActiveRow(null) }), _jsx(AdminPermissionModal, { open: activeRow === "admin-permission", groupID: groupID, onClose: () => setActiveRow(null), inline: true }), (activeRow === "muted-chat-list" || activeRow === "block-list") && (_jsx(Modal, { centered: true, open: true, footer: null, onCancel: () => setActiveRow(null), title: t(activeRow === "muted-chat-list" ? "muted_chat_list" : "block_list"), getContainer: false, children: _jsx("p", { className: "text-sm text-gray-500", children: t("feature_coming_soon") }) }))] }));
185
+ return (_jsxs("div", { className: "h-full w-[330px] bg-white shadow-md flex flex-col relative overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-4 border-b border-gray-100", children: [_jsx("span", { className: "text-lg font-medium", children: t("thread_info_title") }), _jsx("button", { type: "button", className: "flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:bg-gray-100", onClick: onClose, children: _jsx(Icon, { icon: "close-o", size: 20 }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-4", children: [_jsxs("div", { className: "relative shrink-0", children: [_jsx(GroupCompositeAvatar, { groupID: groupID, faceURL: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.faceURL, ownerUserID: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.ownerUserID, groupName: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName, size: 56 }), isAvatarUploading && (_jsx("span", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-black/30", children: _jsx("span", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }) })), permissions.updateGroupAvatar && (_jsxs(_Fragment, { children: [_jsx("input", { ref: avatarInputRef, type: "file", accept: "image/jpeg, image/png, image/jpg", className: "hidden", onChange: handleAvatarSelect }), _jsx("button", { type: "button", disabled: isAvatarUploading, onClick: handleAvatarClick, className: "absolute -bottom-1 -right-1 flex items-center justify-center w-5 h-5 rounded-full bg-black text-white", children: _jsx(Icon, { icon: "camera-o", size: 12 }) })] }))] }), _jsx("div", { className: "flex-1 min-w-0", children: editingField === "name" ? (_jsx(Input, { autoFocus: true, value: nameValue, onChange: (event) => setNameValue(event.target.value), onPressEnter: saveName, onBlur: saveName, maxLength: 100 })) : (_jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("p", { className: "text-base font-medium truncate", children: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName }), permissions.updateGroupName && (_jsx(Icon, { icon: "edit-o", size: 16, className: "shrink-0 cursor-pointer text-gray-500", onClick: startEditName }))] })) })] }), _jsx("div", { className: "px-4 pb-4", children: editingField === "description" ? (_jsxs("div", { className: "flex flex-col gap-3 bg-[#f5f5f5] rounded-lg p-3", children: [_jsxs("span", { className: "flex items-center gap-2 text-sm font-medium text-gray-900", children: [_jsx(Icon, { icon: "info-circle-o", size: 18, className: "text-gray-500" }), t("description")] }), _jsx(Input.TextArea, { autoFocus: true, value: descriptionValue, onChange: (event) => setDescriptionValue(event.target.value), placeholder: t("enter_group_description"), autoSize: { minRows: 1, maxRows: 4 }, maxLength: 500, className: "bg-white" }), _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx("button", { type: "button", className: "px-4 py-1.5 rounded-full border border-primary-500 text-primary-500 text-sm font-medium", onClick: cancelEditDescription, children: t("cancel") }), _jsx("button", { type: "button", className: "px-4 py-1.5 rounded-full text-primary-500 text-sm font-medium disabled:text-gray-300", disabled: descriptionValue.trim() === ((_c = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) !== null && _c !== void 0 ? _c : ""), onClick: saveDescription, children: t("save") })] })] })) : (_jsxs("div", { className: "flex items-start justify-between gap-2 bg-[#f5f5f5] rounded-lg px-3 py-2.5", children: [_jsxs("div", { className: "flex items-start gap-2 flex-1 min-w-0", children: [_jsx(Icon, { icon: "info-circle-o", size: 18, className: "shrink-0 mt-0.5 text-gray-900" }), _jsxs("div", { className: "flex flex-col gap-0.5 min-w-0", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: t("description") }), _jsx("p", { className: "text-sm text-gray-400 truncate", children: (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) || t("no_description") })] })] }), permissions.updateGroupDescription && (_jsx(Icon, { icon: "edit-o", size: 16, className: "shrink-0 cursor-pointer text-gray-500", onClick: startEditDescription }))] })) }), _jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 rounded-lg overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-o", size: 18 }), t("notification")] }), _jsx(Switch, { checked: notifyEnabled, onChange: handleToggleNotification, loading: isTogglingNotification })] }), (config === null || config === void 0 ? void 0 : config.showAllowSendMessage) && (_jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "user-check-o", size: 18 }), t("allow_send_message")] }), _jsx(Switch, { checked: allowSendMessage, onChange: handleToggleSendMessage, loading: isTogglingSendMessage })] })), isAdminOrOwner && (config === null || config === void 0 ? void 0 : config.showMutedChatList) && (_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("muted-chat-list"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-off-o", size: 18 }), t("muted_chat_list")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })), _jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("block-list"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t("block_list")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })] }), permissions.configGroupPermission && (_jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: [_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("member-permission"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "shield-o", size: 18 }), t("member_permission_settings")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] }), _jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("admin-permission"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "shield-done-o", size: 18 }), t("admin_permission_settings")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })] })), _jsx("div", { className: "mx-4 mt-3 rounded-lg overflow-hidden bg-[#f5f5f5]", children: _jsxs("button", { type: "button", className: "w-full flex items-center gap-3 px-3 py-3 text-left text-sm text-gray-400 cursor-not-allowed", disabled: true, title: t("invite_via_link_pending"), children: [_jsx(Icon, { icon: "link-alt-o", size: 18 }), t("invite_via_link")] }) }), _jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 mb-4 rounded-lg overflow-hidden", children: [_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("delete"), children: [_jsx(Icon, { icon: "trash-o", size: 18 }), t("delete_conversation")] }), _jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("leave"), children: [_jsx(Icon, { icon: "logout-o", size: 18 }), t("leave_group")] }), isAdminOrOwner && (_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("disband"), children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t("disband_group")] }))] })] }), _jsx(Modal, { centered: true, open: confirmAction === "leave", onOk: handleConfirmLeave, onCancel: () => setConfirmAction(null), title: t("leave_group_confirm_title"), okText: t("leave_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isLeaving, getContainer: false, forceRender: true, children: _jsx("p", { children: t("leave_group_confirm_message") }) }), _jsx(Modal, { centered: true, open: confirmAction === "disband", onOk: handleConfirmDisband, onCancel: () => setConfirmAction(null), title: t("disband_group_confirm_title"), okText: t("disband_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isDismissing, getContainer: false, forceRender: true, children: _jsx("p", { children: t("disband_group_confirm_message") }) }), _jsx(Modal, { centered: true, open: confirmAction === "delete", onOk: handleConfirmDelete, onCancel: () => setConfirmAction(null), title: t("delete_conversation_confirm_title"), okText: t("delete_conversation"), cancelText: t("cancel"), okType: "danger", confirmLoading: isDeleting, getContainer: false, forceRender: true, children: _jsx("p", { children: t("delete_conversation_confirm_message") }) }), _jsx(MemberPermissionPanel, { open: activeRow === "member-permission", groupID: groupID, onClose: () => setActiveRow(null) }), _jsx(AdminPermissionModal, { open: activeRow === "admin-permission", groupID: groupID, onClose: () => setActiveRow(null), inline: true }), (activeRow === "muted-chat-list" || activeRow === "block-list") && (_jsx(Modal, { centered: true, open: true, footer: null, onCancel: () => setActiveRow(null), title: t(activeRow === "muted-chat-list" ? "muted_chat_list" : "block_list"), getContainer: false, forceRender: true, children: _jsx("p", { className: "text-sm text-gray-500", children: t("feature_coming_soon") }) }))] }));
155
186
  };
156
187
  export default GroupThreadInfo;
@@ -1 +1 @@
1
- {"version":3,"file":"SingleThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/SingleThreadInfo.tsx"],"names":[],"mappings":"AAYA,UAAU,qBAAqB;IAC7B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,gBAAgB,GAAI,aAAa,qBAAqB,mDAmJ3D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"SingleThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/SingleThreadInfo.tsx"],"names":[],"mappings":"AAYA,UAAU,qBAAqB;IAC7B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,gBAAgB,GAAI,aAAa,qBAAqB,mDAoJ3D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -65,6 +65,6 @@ const SingleThreadInfo = ({ onClose }) => {
65
65
  if (!conversationID) {
66
66
  return null;
67
67
  }
68
- return (_jsxs("div", { className: "h-full w-[330px] bg-white shadow-md flex flex-col relative", children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-4 border-b border-gray-100", children: [_jsx("span", { className: "text-lg font-medium", children: t("thread_info_title") }), _jsx("button", { type: "button", className: "flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:bg-gray-100", onClick: onClose, children: _jsx(Icon, { icon: "close-o", size: 20 }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-4", children: [_jsx(Avatar, { src: avatar, size: 56, className: "shrink-0", children: ((_a = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _a === void 0 ? void 0 : _a.call(displayName, 0)) || "A" }), _jsxs("div", { className: "flex-1 min-w-0 flex items-center gap-2", children: [_jsx("p", { className: "text-base font-medium truncate", children: displayName }), isBot && (_jsx("span", { className: "shrink-0 rounded px-1.5 py-0.5 text-xs font-semibold bg-orange-50 text-orange-500", children: t("bot_tag") }))] })] }), _jsx("div", { className: "bg-[#f5f5f5] mx-4 rounded-lg overflow-hidden", children: _jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-o", size: 18 }), t("notification")] }), _jsx(Switch, { checked: notifyEnabled, onChange: handleToggleNotification, loading: isTogglingNotification })] }) }), _jsx("div", { className: "bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: _jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm w-full", onClick: handleToggleBlock, disabled: isTogglingBlock, children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t(isBlocked ? "unblock_user" : "block_user")] }) }), _jsx("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: _jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmDelete(true), children: [_jsx(Icon, { icon: "trash-o", size: 18 }), t("delete_conversation")] }) })] }), _jsx(Modal, { centered: true, open: confirmDelete, onOk: handleConfirmDelete, onCancel: () => setConfirmDelete(false), title: t("delete_conversation_confirm_title"), okText: t("delete_conversation"), cancelText: t("cancel"), okType: "danger", confirmLoading: isDeleting, getContainer: false, children: _jsx("p", { children: t("delete_conversation_confirm_message") }) })] }));
68
+ return (_jsxs("div", { className: "h-full w-[330px] bg-white shadow-md flex flex-col relative", children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-4 border-b border-gray-100", children: [_jsx("span", { className: "text-lg font-medium", children: t("thread_info_title") }), _jsx("button", { type: "button", className: "flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:bg-gray-100", onClick: onClose, children: _jsx(Icon, { icon: "close-o", size: 20 }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-4", children: [_jsx(Avatar, { src: avatar, size: 56, className: "shrink-0", children: ((_a = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _a === void 0 ? void 0 : _a.call(displayName, 0)) || "A" }), _jsxs("div", { className: "flex-1 min-w-0 flex items-center gap-2", children: [_jsx("p", { className: "text-base font-medium truncate", children: displayName }), isBot && (_jsx("span", { className: "shrink-0 rounded px-1.5 py-0.5 text-xs font-semibold bg-orange-50 text-orange-500", children: t("bot_tag") }))] })] }), _jsx("div", { className: "bg-[#f5f5f5] mx-4 rounded-lg overflow-hidden", children: _jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-o", size: 18 }), t("notification")] }), _jsx(Switch, { checked: notifyEnabled, onChange: handleToggleNotification, loading: isTogglingNotification })] }) }), _jsx("div", { className: "bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: _jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm w-full", onClick: handleToggleBlock, disabled: isTogglingBlock, children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t(isBlocked ? "unblock_user" : "block_user")] }) }), _jsx("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: _jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmDelete(true), children: [_jsx(Icon, { icon: "trash-o", size: 18 }), t("delete_conversation")] }) })] }), _jsx(Modal, { centered: true, open: confirmDelete, onOk: handleConfirmDelete, onCancel: () => setConfirmDelete(false), title: t("delete_conversation_confirm_title"), okText: t("delete_conversation"), cancelText: t("cancel"), okType: "danger", confirmLoading: isDeleting, getContainer: false, forceRender: true, children: _jsx("p", { children: t("delete_conversation_confirm_message") }) })] }));
69
69
  };
70
70
  export default SingleThreadInfo;
@@ -1 +1 @@
1
- {"version":3,"file":"ThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/ThreadInfo.tsx"],"names":[],"mappings":"AAGA,OAAwB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAO3E,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAED,QAAA,MAAM,UAAU,GAAI,kCAAyC,eAAe,mDAsD3E,CAAC;AAEF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"ThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/ThreadInfo.tsx"],"names":[],"mappings":"AAGA,OAAwB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAQ3E,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAED,QAAA,MAAM,UAAU,GAAI,kCAAyC,eAAe,mDAsD3E,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -8,10 +8,11 @@ import { useGetListSessionByConversation } from "../../hooks/session/useGetListS
8
8
  import { useMemo } from "react";
9
9
  import { PAGE_SIZE } from "../../constants";
10
10
  import { PeerType } from "../../types/conversation";
11
+ import { isGroupConversation } from "../../utils/imCommon";
11
12
  const ThreadInfo = ({ isOpen = true, onClose, groupConfig }) => {
12
13
  const conversationData = useConversationStore((state) => state.conversationData);
13
14
  const conversationId = (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID) || "";
14
- const isGroup = (conversationData === null || conversationData === void 0 ? void 0 : conversationData.peerType) === PeerType.GROUP;
15
+ const isGroup = isGroupConversation(conversationData !== null && conversationData !== void 0 ? conversationData : undefined);
15
16
  const isBot = (conversationData === null || conversationData === void 0 ? void 0 : conversationData.peerType) === PeerType.BOT;
16
17
  const { data: sessions, isLoading } = useGetListSessionByConversation({
17
18
  conversationId,
@@ -1 +1 @@
1
- {"version":3,"file":"VideoPlayerModal.d.ts","sourceRoot":"","sources":["../../../src/components/video-player/VideoPlayerModal.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,qBAAqB;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAQD,eAAO,MAAM,oBAAoB,GAC/B,OAAO,iBAAiB,EAAE,KACzB,iBAAiB,EAWhB,CAAC;AAEL,QAAA,MAAM,gBAAgB,GAAI,0CAKvB,qBAAqB,4CAqFvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"VideoPlayerModal.d.ts","sourceRoot":"","sources":["../../../src/components/video-player/VideoPlayerModal.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,qBAAqB;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAQD,eAAO,MAAM,oBAAoB,GAC/B,OAAO,iBAAiB,EAAE,KACzB,iBAAiB,EAWhB,CAAC;AAEL,QAAA,MAAM,gBAAgB,GAAI,0CAKvB,qBAAqB,4CAsFvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -34,7 +34,7 @@ const VideoPlayerModal = ({ open, videos, initialIndex, onClose, }) => {
34
34
  const currentVideo = videos[currentIndex];
35
35
  const { snapshotWidth = 0, snapshotHeight = 0 } = currentVideo || {};
36
36
  const hasSnapshotSize = snapshotWidth > 0 && snapshotHeight > 0;
37
- return (_jsx(Modal, { open: open, onCancel: onClose, footer: null, centered: true, destroyOnHidden: true, getContainer: false, closeIcon: _jsx("span", { className: CLOSE_BUTTON_CLASS, children: _jsx(Icon, { icon: "close-b", size: 18 }) }), styles: {
37
+ return (_jsx(Modal, { open: open, onCancel: onClose, footer: null, centered: true, destroyOnHidden: true, getContainer: false, forceRender: true, closeIcon: _jsx("span", { className: CLOSE_BUTTON_CLASS, children: _jsx(Icon, { icon: "close-b", size: 18 }) }), styles: {
38
38
  content: {
39
39
  padding: 0,
40
40
  },
@@ -0,0 +1,3 @@
1
+ import type { IUploadedFile } from "../../types/dto";
2
+ export declare const useUploadFile: () => import("@tanstack/react-query").UseMutationResult<IUploadedFile, Error, File, unknown>;
3
+ //# sourceMappingURL=useUploadFile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useUploadFile.d.ts","sourceRoot":"","sources":["../../../src/hooks/common/useUploadFile.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,aAAa,CAAC;AAI/D,eAAO,MAAM,aAAa,8FAgBtB,CAAC"}