@droppii-org/chat-sdk 0.1.97 → 0.2.1

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 (138) hide show
  1. package/dist/assets/images/muteNotificationWarning.png +0 -0
  2. package/dist/components/compose/ComposeNewMessageModal.d.ts.map +1 -1
  3. package/dist/components/compose/ComposeNewMessageModal.js +1 -1
  4. package/dist/components/conversation/SwipeActionButton.d.ts +11 -0
  5. package/dist/components/conversation/SwipeActionButton.d.ts.map +1 -0
  6. package/dist/components/conversation/SwipeActionButton.js +7 -0
  7. package/dist/components/conversation/SwipeableRow.d.ts +10 -0
  8. package/dist/components/conversation/SwipeableRow.d.ts.map +1 -0
  9. package/dist/components/conversation/SwipeableRow.js +62 -0
  10. package/dist/components/conversation/ThreadCard.d.ts +2 -1
  11. package/dist/components/conversation/ThreadCard.d.ts.map +1 -1
  12. package/dist/components/conversation/ThreadCard.js +2 -2
  13. package/dist/components/conversation-inbox/ConversationInboxItem.d.ts.map +1 -1
  14. package/dist/components/conversation-inbox/ConversationInboxItem.js +14 -1
  15. package/dist/components/conversation-inbox/ConversationMuteSwipeAction.d.ts +8 -0
  16. package/dist/components/conversation-inbox/ConversationMuteSwipeAction.d.ts.map +1 -0
  17. package/dist/components/conversation-inbox/ConversationMuteSwipeAction.js +31 -0
  18. package/dist/components/conversation-inbox/MuteConversationConfirmModal.d.ts +9 -0
  19. package/dist/components/conversation-inbox/MuteConversationConfirmModal.d.ts.map +1 -0
  20. package/dist/components/conversation-inbox/MuteConversationConfirmModal.js +13 -0
  21. package/dist/components/conversation-inbox/index.d.ts +4 -0
  22. package/dist/components/conversation-inbox/index.d.ts.map +1 -1
  23. package/dist/components/conversation-inbox/index.js +2 -0
  24. package/dist/components/group/AddMemberModal.d.ts +9 -0
  25. package/dist/components/group/AddMemberModal.d.ts.map +1 -0
  26. package/dist/components/group/AddMemberModal.js +70 -0
  27. package/dist/components/group/AdminPermissionModal.d.ts +9 -0
  28. package/dist/components/group/AdminPermissionModal.d.ts.map +1 -0
  29. package/dist/components/group/AdminPermissionModal.js +63 -0
  30. package/dist/components/group/CreateGroupForm.d.ts +1 -2
  31. package/dist/components/group/CreateGroupForm.d.ts.map +1 -1
  32. package/dist/components/group/CreateGroupForm.js +4 -4
  33. package/dist/components/group/GroupMemberPicker.d.ts.map +1 -1
  34. package/dist/components/group/GroupMemberPicker.js +16 -8
  35. package/dist/components/group/MemberPermissionPanel.d.ts +8 -0
  36. package/dist/components/group/MemberPermissionPanel.d.ts.map +1 -0
  37. package/dist/components/group/MemberPermissionPanel.js +53 -0
  38. package/dist/components/media-resources/FileResourceList.js +1 -1
  39. package/dist/components/media-resources/LinkResourceItem.js +1 -1
  40. package/dist/components/message/GroupMembersDrawer.d.ts.map +1 -1
  41. package/dist/components/message/GroupMembersDrawer.js +210 -28
  42. package/dist/components/message/MessageHeader.d.ts +2 -1
  43. package/dist/components/message/MessageHeader.d.ts.map +1 -1
  44. package/dist/components/message/MessageHeader.js +7 -2
  45. package/dist/components/message/MessageList.d.ts +1 -0
  46. package/dist/components/message/MessageList.d.ts.map +1 -1
  47. package/dist/components/message/MessageList.js +7 -2
  48. package/dist/components/message/SelectSession.d.ts.map +1 -1
  49. package/dist/components/message/SelectSession.js +3 -3
  50. package/dist/components/session/DeskTeamInbox.js +1 -1
  51. package/dist/components/thread/GroupThreadInfo.d.ts +11 -0
  52. package/dist/components/thread/GroupThreadInfo.d.ts.map +1 -0
  53. package/dist/components/thread/GroupThreadInfo.js +156 -0
  54. package/dist/components/thread/ManualAssignPopover.js +2 -2
  55. package/dist/components/thread/SessionSection.d.ts.map +1 -1
  56. package/dist/components/thread/SessionSection.js +2 -8
  57. package/dist/components/thread/SingleThreadInfo.d.ts +6 -0
  58. package/dist/components/thread/SingleThreadInfo.d.ts.map +1 -0
  59. package/dist/components/thread/SingleThreadInfo.js +70 -0
  60. package/dist/components/thread/ThreadInfo.d.ts +7 -1
  61. package/dist/components/thread/ThreadInfo.d.ts.map +1 -1
  62. package/dist/components/thread/ThreadInfo.js +14 -2
  63. package/dist/constants/images.d.ts +1 -0
  64. package/dist/constants/images.d.ts.map +1 -1
  65. package/dist/constants/images.js +2 -0
  66. package/dist/constants/index.d.ts +1 -0
  67. package/dist/constants/index.d.ts.map +1 -1
  68. package/dist/constants/index.js +3 -0
  69. package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
  70. package/dist/hooks/global/useGlobalEvent.js +27 -0
  71. package/dist/hooks/group/useAddGroupMember.d.ts +7 -0
  72. package/dist/hooks/group/useAddGroupMember.d.ts.map +1 -0
  73. package/dist/hooks/group/useAddGroupMember.js +20 -0
  74. package/dist/hooks/group/useDismissGroup.d.ts +4 -0
  75. package/dist/hooks/group/useDismissGroup.d.ts.map +1 -0
  76. package/dist/hooks/group/useDismissGroup.js +22 -0
  77. package/dist/hooks/group/useEligibleAccounts.d.ts +3 -0
  78. package/dist/hooks/group/useEligibleAccounts.d.ts.map +1 -1
  79. package/dist/hooks/group/useEligibleAccounts.js +9 -9
  80. package/dist/hooks/group/useEligibleAccountsForGroup.d.ts +9 -0
  81. package/dist/hooks/group/useEligibleAccountsForGroup.d.ts.map +1 -0
  82. package/dist/hooks/group/useEligibleAccountsForGroup.js +26 -0
  83. package/dist/hooks/group/useGetGroupCandidates.d.ts +7 -2
  84. package/dist/hooks/group/useGetGroupCandidates.d.ts.map +1 -1
  85. package/dist/hooks/group/useGetGroupCandidates.js +33 -16
  86. package/dist/hooks/group/useGroupMemberActions.d.ts +25 -0
  87. package/dist/hooks/group/useGroupMemberActions.d.ts.map +1 -0
  88. package/dist/hooks/group/useGroupMemberActions.js +54 -0
  89. package/dist/hooks/group/useGroupPermission.d.ts +15 -0
  90. package/dist/hooks/group/useGroupPermission.d.ts.map +1 -0
  91. package/dist/hooks/group/useGroupPermission.js +70 -0
  92. package/dist/hooks/group/useSearchGroupMembers.d.ts +8 -0
  93. package/dist/hooks/group/useSearchGroupMembers.d.ts.map +1 -0
  94. package/dist/hooks/group/useSearchGroupMembers.js +37 -0
  95. package/dist/hooks/group/useSetMemberPermission.d.ts +12 -0
  96. package/dist/hooks/group/useSetMemberPermission.d.ts.map +1 -0
  97. package/dist/hooks/group/useSetMemberPermission.js +32 -0
  98. package/dist/hooks/group/useToggleGroupSendMessage.d.ts +7 -0
  99. package/dist/hooks/group/useToggleGroupSendMessage.d.ts.map +1 -0
  100. package/dist/hooks/group/useToggleGroupSendMessage.js +22 -0
  101. package/dist/hooks/group/useUpdateGroupInfo.d.ts +7 -0
  102. package/dist/hooks/group/useUpdateGroupInfo.d.ts.map +1 -0
  103. package/dist/hooks/group/useUpdateGroupInfo.js +15 -0
  104. package/dist/hooks/session/useBlockUser.d.ts +10 -0
  105. package/dist/hooks/session/useBlockUser.d.ts.map +1 -0
  106. package/dist/hooks/session/useBlockUser.js +49 -0
  107. package/dist/hooks/session/useDeleteConversation.d.ts +4 -0
  108. package/dist/hooks/session/useDeleteConversation.d.ts.map +1 -0
  109. package/dist/hooks/session/useDeleteConversation.js +20 -0
  110. package/dist/hooks/session/useGetListSessionByConversation.d.ts +2 -1
  111. package/dist/hooks/session/useGetListSessionByConversation.d.ts.map +1 -1
  112. package/dist/hooks/session/useGetListSessionByConversation.js +2 -2
  113. package/dist/hooks/session/useMuteConversation.d.ts +8 -0
  114. package/dist/hooks/session/useMuteConversation.d.ts.map +1 -0
  115. package/dist/hooks/session/useMuteConversation.js +37 -0
  116. package/dist/hooks/session/useToggleConversationNotification.d.ts +7 -0
  117. package/dist/hooks/session/useToggleConversationNotification.d.ts.map +1 -0
  118. package/dist/hooks/session/useToggleConversationNotification.js +15 -0
  119. package/dist/index.d.ts +2 -0
  120. package/dist/index.d.ts.map +1 -1
  121. package/dist/index.js +2 -0
  122. package/dist/locales/vi/common.json +63 -1
  123. package/dist/locales/vi/conversation-inbox.json +22 -0
  124. package/dist/screens/desk-message/index.d.ts +3 -1
  125. package/dist/screens/desk-message/index.d.ts.map +1 -1
  126. package/dist/screens/desk-message/index.js +4 -5
  127. package/dist/services/query.d.ts +2 -0
  128. package/dist/services/query.d.ts.map +1 -1
  129. package/dist/services/query.js +2 -0
  130. package/dist/store/groupPermissionOverrides.d.ts +23 -0
  131. package/dist/store/groupPermissionOverrides.d.ts.map +1 -0
  132. package/dist/store/groupPermissionOverrides.js +12 -0
  133. package/dist/styles/global.css +1 -1
  134. package/dist/utils/events.d.ts +1 -0
  135. package/dist/utils/events.d.ts.map +1 -1
  136. package/dist/utils/imCommon.d.ts +1 -0
  137. package/dist/utils/imCommon.d.ts.map +1 -1
  138. package/package.json +3 -2
@@ -0,0 +1,8 @@
1
+ interface MemberPermissionPanelProps {
2
+ open: boolean;
3
+ groupID: string;
4
+ onClose: () => void;
5
+ }
6
+ declare const MemberPermissionPanel: ({ open, groupID, onClose }: MemberPermissionPanelProps) => import("react/jsx-runtime").JSX.Element | null;
7
+ export default MemberPermissionPanel;
8
+ //# sourceMappingURL=MemberPermissionPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemberPermissionPanel.d.ts","sourceRoot":"","sources":["../../../src/components/group/MemberPermissionPanel.tsx"],"names":[],"mappings":"AAYA,UAAU,0BAA0B;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAMD,QAAA,MAAM,qBAAqB,GAAI,4BAA4B,0BAA0B,mDAqHpF,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,53 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { ConfigProvider, Switch, message } from "antd";
5
+ import { useTranslation } from "react-i18next";
6
+ import { useGroupPermission } from "../../hooks/group/useGroupPermission";
7
+ import { Icon } from "../../components/icon";
8
+ import { PERMISSION_SWITCH_COLOR } from "../../constants";
9
+ import useGroupPermissionOverridesStore from "../../store/groupPermissionOverrides";
10
+ // Mocked config UI (DROPPII-30248 follow-up, "Configure Member Permissions")
11
+ // — renders inline within the "Thông tin" sidebar (back arrow, no gray
12
+ // background) per the reference recording, not as a Modal popup. No BE
13
+ // persistence yet, committed to the in-memory override store on "Lưu" only.
14
+ const MemberPermissionPanel = ({ open, groupID, onClose }) => {
15
+ const { t } = useTranslation();
16
+ const permissions = useGroupPermission(groupID);
17
+ const setMemberOverrides = useGroupPermissionOverridesStore((state) => state.setMemberOverrides);
18
+ const [isSaving, setIsSaving] = useState(false);
19
+ const [pending, setPending] = useState({
20
+ sendMessage: permissions.sendMessage,
21
+ addMember: permissions.addMember,
22
+ pinMessage: permissions.pinMessage,
23
+ viewMemberInformation: permissions.viewMemberInformation,
24
+ });
25
+ useEffect(() => {
26
+ if (!open)
27
+ return;
28
+ setPending({
29
+ sendMessage: permissions.sendMessage,
30
+ addMember: permissions.addMember,
31
+ pinMessage: permissions.pinMessage,
32
+ viewMemberInformation: permissions.viewMemberInformation,
33
+ });
34
+ // eslint-disable-next-line react-hooks/exhaustive-deps
35
+ }, [open]);
36
+ const hasChanges = pending.sendMessage !== permissions.sendMessage ||
37
+ pending.addMember !== permissions.addMember ||
38
+ pending.pinMessage !== permissions.pinMessage ||
39
+ pending.viewMemberInformation !== permissions.viewMemberInformation;
40
+ const handleSave = async () => {
41
+ if (!groupID)
42
+ return;
43
+ setIsSaving(true);
44
+ setMemberOverrides(groupID, pending);
45
+ message.success(t("update_member_permissions_success"));
46
+ setIsSaving(false);
47
+ onClose();
48
+ };
49
+ if (!open)
50
+ return null;
51
+ return (_jsxs("div", { className: "absolute inset-0 bg-white flex flex-col z-10", children: [_jsxs("div", { className: "flex w-full items-center border-b border-gray-100 p-2", children: [_jsx("button", { type: "button", className: "flex shrink-0 cursor-pointer items-center justify-center p-2 text-primary-400", onClick: onClose, children: _jsx(Icon, { icon: "arrow-left-o", size: 24 }) }), _jsx("p", { className: "min-w-0 flex-1 truncate px-2 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("member_permission_settings") })] }), _jsx("div", { className: "flex-1 overflow-y-auto", children: _jsx(ConfigProvider, { theme: { token: { colorPrimary: PERMISSION_SWITCH_COLOR } }, children: _jsxs("div", { className: "flex flex-col py-2", children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-3", children: [_jsx("span", { className: "text-sm", children: t("permission_send_message") }), _jsx(Switch, { checked: pending.sendMessage, onChange: (checked) => setPending((prev) => (Object.assign(Object.assign({}, prev), { sendMessage: checked }))) })] }), _jsxs("div", { className: "flex items-center justify-between px-4 py-3", children: [_jsx("span", { className: "text-sm", children: t("permission_add_member") }), _jsx(Switch, { checked: pending.addMember, onChange: (checked) => setPending((prev) => (Object.assign(Object.assign({}, prev), { addMember: checked }))) })] }), _jsxs("div", { className: "flex items-center justify-between px-4 py-3", children: [_jsx("span", { className: "text-sm", children: t("permission_pin_message") }), _jsx(Switch, { checked: pending.pinMessage, onChange: (checked) => setPending((prev) => (Object.assign(Object.assign({}, prev), { pinMessage: checked }))) })] }), _jsxs("div", { className: "flex items-center justify-between px-4 py-3", children: [_jsx("span", { className: "text-sm", children: t("permission_view_member_info") }), _jsx(Switch, { checked: pending.viewMemberInformation, onChange: (checked) => setPending((prev) => (Object.assign(Object.assign({}, prev), { viewMemberInformation: checked }))) })] })] }) }) }), _jsxs("div", { className: "flex items-center justify-end gap-2 px-4 py-3 border-t border-gray-100", children: [_jsx("button", { type: "button", className: "px-4 py-1.5 rounded-full border border-gray-300 text-gray-700 text-sm font-medium", onClick: onClose, children: t("cancel") }), _jsx("button", { type: "button", className: "px-4 py-1.5 rounded-full bg-primary-400 text-white text-sm font-medium disabled:bg-gray-200 disabled:text-gray-400", disabled: !hasChanges || isSaving, onClick: handleSave, children: t("save") })] })] }));
52
+ };
53
+ export default MemberPermissionPanel;
@@ -11,7 +11,7 @@ const FileResourceList = () => {
11
11
  return (_jsx(ResourceScrollContainer, Object.assign({}, containerProps, { itemCount: items.length, children: _jsx("div", { className: "flex flex-col gap-2 p-3", children: items.map((item) => {
12
12
  var _a, _b;
13
13
  const fileContent = parseMessageContent((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content);
14
- return (_jsxs("div", { className: "flex w-full cursor-pointer items-center gap-2 rounded-[12px] bg-gray-50/20 p-3", onClick: () => downloadFileFromUrl((fileContent === null || fileContent === void 0 ? void 0 : fileContent.sourceUrl) || "", (fileContent === null || fileContent === void 0 ? void 0 : fileContent.fileName) || ""), children: [_jsx("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center [&>svg]:h-full [&>svg]:w-auto", children: documentIcon }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("span", { className: "truncate text-[16px] font-medium leading-[1.6] text-gray-900", children: shortenFileName(fileContent === null || fileContent === void 0 ? void 0 : fileContent.fileName) }), _jsx("span", { className: "text-[13px] font-normal leading-[1.6] text-gray-400", children: renderFileSize((fileContent === null || fileContent === void 0 ? void 0 : fileContent.fileSize) || 0) })] })] }, (_b = item.chatLog) === null || _b === void 0 ? void 0 : _b.clientMsgID));
14
+ return (_jsxs("div", { className: "flex w-full cursor-pointer items-center gap-2 rounded-[12px] bg-[#f5f5f5]/20 p-3", onClick: () => downloadFileFromUrl((fileContent === null || fileContent === void 0 ? void 0 : fileContent.sourceUrl) || "", (fileContent === null || fileContent === void 0 ? void 0 : fileContent.fileName) || ""), children: [_jsx("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center [&>svg]:h-full [&>svg]:w-auto", children: documentIcon }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("span", { className: "truncate text-[16px] font-medium leading-[1.6] text-gray-900", children: shortenFileName(fileContent === null || fileContent === void 0 ? void 0 : fileContent.fileName) }), _jsx("span", { className: "text-[13px] font-normal leading-[1.6] text-gray-400", children: renderFileSize((fileContent === null || fileContent === void 0 ? void 0 : fileContent.fileSize) || 0) })] })] }, (_b = item.chatLog) === null || _b === void 0 ? void 0 : _b.clientMsgID));
15
15
  }) }) })));
16
16
  };
17
17
  export default FileResourceList;
@@ -17,6 +17,6 @@ const LinkResourceItem = ({ url, messageMetadata }) => {
17
17
  const handleOpen = () => {
18
18
  openLink(url, t);
19
19
  };
20
- return (_jsxs("div", { "data-testid": "link-resource-item", className: "flex w-full cursor-pointer items-center gap-2 rounded-[12px] bg-gray-50/20 p-3", onClick: handleOpen, children: [_jsx("div", { className: "flex h-[76px] w-[76px] shrink-0 items-center justify-center", children: shouldShowImage ? (_jsx("img", { src: imageUrl, alt: "", className: "h-full w-full rounded-[8px] object-cover", onError: () => setFailedImageUrl(imageUrl) })) : (_jsx("div", { className: "flex h-full w-full items-center justify-center rounded-[12px] bg-gray-200", children: _jsx(Icon, { icon: "link-b", size: 24, color: "white" }) })) }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col justify-center", children: [_jsx("p", { className: "truncate text-[14px] font-normal leading-[1.6] tracking-[-0.14px] text-gray-600", children: stripProtocol(url) }), _jsx("p", { className: "line-clamp-2 text-[16px] font-medium leading-[1.6] text-gray-900", children: title || url })] })] }));
20
+ return (_jsxs("div", { "data-testid": "link-resource-item", className: "flex w-full cursor-pointer items-center gap-2 rounded-[12px] bg-[#f5f5f5]/20 p-3", onClick: handleOpen, children: [_jsx("div", { className: "flex h-[76px] w-[76px] shrink-0 items-center justify-center", children: shouldShowImage ? (_jsx("img", { src: imageUrl, alt: "", className: "h-full w-full rounded-[8px] object-cover", onError: () => setFailedImageUrl(imageUrl) })) : (_jsx("div", { className: "flex h-full w-full items-center justify-center rounded-[12px] bg-gray-200", children: _jsx(Icon, { icon: "link-b", size: 24, color: "white" }) })) }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col justify-center", children: [_jsx("p", { className: "truncate text-[14px] font-normal leading-[1.6] tracking-[-0.14px] text-gray-600", children: stripProtocol(url) }), _jsx("p", { className: "line-clamp-2 text-[16px] font-medium leading-[1.6] text-gray-900", children: title || url })] })] }));
21
21
  };
22
22
  export default LinkResourceItem;
@@ -1 +1 @@
1
- {"version":3,"file":"GroupMembersDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/message/GroupMembersDrawer.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAK/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;AAsCD,QAAA,MAAM,kBAAkB,GAAI,wDAKzB,uBAAuB,4CA0OzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"GroupMembersDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/message/GroupMembersDrawer.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAe/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;AA4CD,QAAA,MAAM,kBAAkB,GAAI,wDAKzB,uBAAuB,4CAuezB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -1,14 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { GroupMemberRole } from "@droppii-org/wasm-client-sdk";
3
- import { Avatar, Button, Drawer, Dropdown, Empty, message, Modal, Spin } from "antd";
3
+ import { Avatar, Button, Drawer, Dropdown, Empty, Input, message, Modal, Spin } from "antd";
4
4
  import { useEffect, useMemo, useState } from "react";
5
+ import { useDebounce } from "ahooks";
5
6
  import { useTranslation } from "react-i18next";
6
7
  import { usePathname, useRouter } from "next/navigation";
7
8
  import useAuthStore from "../../store/auth";
8
9
  import useConversationStore from "../../store/conversation";
9
10
  import { useGroupMembers } from "../../hooks/group/useGroupMembers";
11
+ import { useSearchGroupMembers } from "../../hooks/group/useSearchGroupMembers";
10
12
  import { useLeaveConversation } from "../../hooks/session/useLeaveConversation";
13
+ import { useGroupPermission } from "../../hooks/group/useGroupPermission";
14
+ import { useKickGroupMember, useMuteGroupMember, useSetGroupMemberRole, useTransferGroupOwner, } from "../../hooks/group/useGroupMemberActions";
11
15
  import { Icon } from "../../components/icon";
16
+ import AddMemberModal from "../../components/group/AddMemberModal";
17
+ import AdminPermissionModal from "../../components/group/AdminPermissionModal";
18
+ const isMemberMuted = (member) => Boolean(member.muteEndTime) && member.muteEndTime * 1000 > Date.now();
12
19
  const getMemberDisplayName = (member) => {
13
20
  return member.nickname || member.userID || "";
14
21
  };
@@ -29,10 +36,24 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
29
36
  const pathname = usePathname();
30
37
  const [isOpen, setIsOpen] = useState(false);
31
38
  const [showLeaveConfirm, setShowLeaveConfirm] = useState(false);
39
+ const [showAddMember, setShowAddMember] = useState(false);
40
+ const [showAdminPermission, setShowAdminPermission] = useState(false);
41
+ const [confirmMemberAction, setConfirmMemberAction] = useState(null);
42
+ const [search, setSearch] = useState("");
43
+ const debouncedSearch = useDebounce(search, { wait: 300 });
32
44
  const authUserID = useAuthStore((state) => state.userID);
33
45
  const conversationData = useConversationStore((state) => state.conversationData);
46
+ const currentMemberInGroup = useConversationStore((state) => state.currentMemberInGroup);
34
47
  const { members, isLoading, error, refetch } = useGroupMembers(groupID);
48
+ const { results: searchResults, isSearching } = useSearchGroupMembers(groupID, debouncedSearch);
35
49
  const { mutateAsync: leaveConversation, isPending: isLeaving } = useLeaveConversation();
50
+ const permissions = useGroupPermission(groupID);
51
+ const { mutateAsync: muteMember } = useMuteGroupMember();
52
+ const { mutateAsync: kickMember } = useKickGroupMember();
53
+ const { mutateAsync: setMemberRole } = useSetGroupMemberRole();
54
+ const { mutateAsync: transferOwner } = useTransferGroupOwner();
55
+ const canAddMember = (currentMemberInGroup === null || currentMemberInGroup === void 0 ? void 0 : currentMemberInGroup.roleLevel) === GroupMemberRole.Admin ||
56
+ (currentMemberInGroup === null || currentMemberInGroup === void 0 ? void 0 : currentMemberInGroup.roleLevel) === GroupMemberRole.Owner;
36
57
  let customerUserID = "";
37
58
  try {
38
59
  const exConversationInfo = JSON.parse((conversationData === null || conversationData === void 0 ? void 0 : conversationData.ex) || "{}");
@@ -41,21 +62,33 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
41
62
  catch (error) {
42
63
  console.error("Error parsing conversation extra info:", error);
43
64
  }
65
+ const isSearchActive = debouncedSearch.trim().length > 0;
66
+ const sourceMembers = isSearchActive ? searchResults : members;
44
67
  const sortedMembers = useMemo(() => {
45
- return [...members]
46
- .map((member) => ({
47
- userID: member.userID,
48
- nickname: getMemberDisplayName(member),
49
- faceURL: member.faceURL,
50
- isCustomer: Boolean(customerUserID) && member.userID === customerUserID,
51
- isCurrentUser: member.userID === authUserID,
52
- roleLabel: getMemberRoleLabel({
53
- member,
54
- customerUserID,
55
- t,
56
- }),
57
- }))
68
+ return [...sourceMembers]
69
+ .map((member) => {
70
+ const isOwner = member.userID === customerUserID ||
71
+ member.roleLevel === GroupMemberRole.Owner;
72
+ return {
73
+ userID: member.userID,
74
+ nickname: getMemberDisplayName(member),
75
+ faceURL: member.faceURL,
76
+ isCustomer: Boolean(customerUserID) && member.userID === customerUserID,
77
+ isCurrentUser: member.userID === authUserID,
78
+ isOwner,
79
+ isAdmin: member.roleLevel === GroupMemberRole.Admin,
80
+ isMuted: isMemberMuted(member),
81
+ // Mockup only shows a role label under the owner/creator row —
82
+ // Admin/Member rows show name only.
83
+ roleLabel: isOwner
84
+ ? getMemberRoleLabel({ member, customerUserID, t })
85
+ : "",
86
+ };
87
+ })
58
88
  .sort((memberA, memberB) => {
89
+ if (memberA.isCurrentUser !== memberB.isCurrentUser) {
90
+ return memberA.isCurrentUser ? -1 : 1;
91
+ }
59
92
  if (memberA.isCustomer !== memberB.isCustomer) {
60
93
  return memberA.isCustomer ? -1 : 1;
61
94
  }
@@ -63,7 +96,7 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
63
96
  sensitivity: "base",
64
97
  });
65
98
  });
66
- }, [authUserID, members, customerUserID, t]);
99
+ }, [authUserID, sourceMembers, customerUserID, t]);
67
100
  const handleOpenDrawer = () => {
68
101
  if (!groupID || disabled) {
69
102
  return;
@@ -86,6 +119,79 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
86
119
  }
87
120
  setShowLeaveConfirm(true);
88
121
  };
122
+ const handleToggleMuteMember = async (member) => {
123
+ var _a, _b;
124
+ if (!groupID)
125
+ return;
126
+ try {
127
+ await muteMember({
128
+ groupID,
129
+ userID: member.userID,
130
+ mute: !member.isMuted,
131
+ });
132
+ message.success(member.isMuted
133
+ ? t("unmute_member_success")
134
+ : t("mute_member_success"));
135
+ void refetch();
136
+ }
137
+ catch (error) {
138
+ 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"));
139
+ }
140
+ };
141
+ const handleConfirmRemoveMember = async () => {
142
+ var _a, _b;
143
+ if (!groupID || (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) !== "remove")
144
+ return;
145
+ try {
146
+ await kickMember({ groupID, userID: confirmMemberAction.member.userID });
147
+ message.success(t("remove_member_success"));
148
+ void refetch();
149
+ }
150
+ catch (error) {
151
+ 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("remove_member_failed"));
152
+ }
153
+ finally {
154
+ setConfirmMemberAction(null);
155
+ }
156
+ };
157
+ const handleToggleAdminRole = async (member) => {
158
+ var _a, _b;
159
+ if (!groupID)
160
+ return;
161
+ try {
162
+ await setMemberRole({
163
+ groupID,
164
+ userID: member.userID,
165
+ roleLevel: member.isAdmin ? GroupMemberRole.Normal : GroupMemberRole.Admin,
166
+ });
167
+ message.success(member.isAdmin
168
+ ? t("remove_from_admin_success")
169
+ : t("assign_as_admin_success"));
170
+ void refetch();
171
+ }
172
+ catch (error) {
173
+ 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"));
174
+ }
175
+ };
176
+ const handleConfirmTransferOwner = async () => {
177
+ var _a, _b;
178
+ if (!groupID || (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) !== "transfer-owner")
179
+ return;
180
+ try {
181
+ await transferOwner({
182
+ groupID,
183
+ newOwnerUserID: confirmMemberAction.member.userID,
184
+ });
185
+ message.success(t("transfer_owner_success"));
186
+ void refetch();
187
+ }
188
+ catch (error) {
189
+ 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"));
190
+ }
191
+ finally {
192
+ setConfirmMemberAction(null);
193
+ }
194
+ };
89
195
  const handleConfirmLeave = async () => {
90
196
  var _a, _b;
91
197
  if (!conversationId || !groupID)
@@ -106,26 +212,98 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
106
212
  setIsOpen(false);
107
213
  }, [groupID]);
108
214
  const renderContent = () => {
109
- if (isLoading) {
215
+ if (isLoading || (isSearchActive && isSearching)) {
110
216
  return (_jsx("div", { className: "flex items-center justify-center h-full min-h-40", children: _jsx(Spin, {}) }));
111
217
  }
112
218
  if (error) {
113
219
  return (_jsx("div", { className: "flex items-center justify-center h-full min-h-40 px-6 text-center text-sm text-gray-500", children: t(error) }));
114
220
  }
115
221
  if (!sortedMembers.length) {
116
- return _jsx(Empty, { description: t("no_group_members") });
222
+ return (_jsx(Empty, { description: isSearchActive ? t("no_member_found") : t("no_group_members") }));
117
223
  }
118
224
  return (_jsx("div", { className: "flex flex-col", children: sortedMembers.map((member) => {
119
- const menuItems = [
120
- {
121
- key: "leave-group",
122
- label: t("leave_group"),
123
- icon: _jsx(Icon, { icon: "logout-b", size: 16 }),
124
- onClick: handleLeaveGroup,
125
- danger: true,
126
- },
127
- ];
128
- return (_jsxs("div", { className: "flex items-center gap-3 px-4 py-3 border-b border-gray-100", 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-medium text-gray-900 truncate", children: member.nickname }), member.isCurrentUser && (_jsx("span", { className: "text-xs text-blue-500 shrink-0", children: t("current_account") }))] }), _jsx("p", { className: "text-sm text-gray-500 truncate", children: member.roleLabel })] }), 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));
225
+ // Send message / Remove and block are not wired yet (no confirmed
226
+ // SDK flow for member-scoped block) — kept disabled per scope.
227
+ const menuItems = member.isCurrentUser
228
+ ? [
229
+ {
230
+ key: "mute",
231
+ label: t("mute_member"),
232
+ icon: _jsx(Icon, { icon: "bell-off-b", size: 16 }),
233
+ disabled: true,
234
+ },
235
+ {
236
+ key: "leave-group",
237
+ label: t("leave_group"),
238
+ icon: _jsx(Icon, { icon: "logout-b", size: 16 }),
239
+ onClick: handleLeaveGroup,
240
+ danger: true,
241
+ },
242
+ ]
243
+ : [
244
+ {
245
+ key: "send-message",
246
+ label: t("send_message"),
247
+ icon: _jsx(Icon, { icon: "send-b", size: 16 }),
248
+ disabled: true,
249
+ },
250
+ {
251
+ key: "mute",
252
+ label: member.isMuted ? t("unmute_member") : t("mute_member"),
253
+ icon: _jsx(Icon, { icon: "bell-off-b", size: 16 }),
254
+ disabled: !permissions.removeMember,
255
+ onClick: () => void handleToggleMuteMember(member),
256
+ },
257
+ {
258
+ key: "transfer-owner",
259
+ label: t("transfer_owner"),
260
+ icon: _jsx(Icon, { icon: "key-b", size: 16 }),
261
+ disabled: !permissions.transferOwnership,
262
+ onClick: () => setConfirmMemberAction({ type: "transfer-owner", member }),
263
+ },
264
+ ...(member.isAdmin
265
+ ? [
266
+ {
267
+ key: "configure-admin-permission",
268
+ label: t("admin_permission_settings"),
269
+ icon: _jsx(Icon, { icon: "shield-o", size: 16 }),
270
+ disabled: !permissions.transferOwnership,
271
+ onClick: () => setShowAdminPermission(true),
272
+ },
273
+ {
274
+ key: "remove-admin",
275
+ label: t("remove_from_admin"),
276
+ icon: _jsx(Icon, { icon: "shield-fail-b", size: 16 }),
277
+ disabled: !permissions.addAdmin,
278
+ onClick: () => void handleToggleAdminRole(member),
279
+ },
280
+ ]
281
+ : [
282
+ {
283
+ key: "assign-admin",
284
+ label: t("assign_as_admin"),
285
+ icon: _jsx(Icon, { icon: "shield-b", size: 16 }),
286
+ disabled: !permissions.addAdmin,
287
+ onClick: () => void handleToggleAdminRole(member),
288
+ },
289
+ ]),
290
+ {
291
+ key: "remove-member",
292
+ label: t("remove_from_group"),
293
+ icon: _jsx(Icon, { icon: "user-del-b", size: 16 }),
294
+ danger: true,
295
+ disabled: !permissions.removeMember,
296
+ onClick: () => setConfirmMemberAction({ type: "remove", member }),
297
+ },
298
+ {
299
+ key: "remove-and-block",
300
+ label: t("remove_and_block"),
301
+ icon: _jsx(Icon, { icon: "user-octagon-b", size: 16 }),
302
+ danger: true,
303
+ disabled: true,
304
+ },
305
+ ];
306
+ 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));
129
307
  }) }));
130
308
  };
131
309
  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: {
@@ -133,6 +311,10 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
133
311
  padding: 0,
134
312
  height: "100%",
135
313
  },
136
- }, 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-3 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 }) })] }), _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") }) })] }));
314
+ }, getContainer: false, width: 360, children: _jsxs("div", { className: "flex flex-col h-full bg-white py-2", 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", {
315
+ name: confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.member.nickname,
316
+ }) }) }), _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", {
317
+ name: confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.member.nickname,
318
+ }) }) }), groupID && (_jsx(AddMemberModal, { open: showAddMember, groupID: groupID, existingMemberIDs: members.map((member) => member.userID), onClose: () => setShowAddMember(false) })), groupID && (_jsx(AdminPermissionModal, { open: showAdminPermission, groupID: groupID, onClose: () => setShowAdminPermission(false) }))] }));
137
319
  };
138
320
  export default GroupMembersDrawer;
@@ -4,6 +4,7 @@ interface MessageHeaderProps {
4
4
  onClose?: () => void;
5
5
  currentSession?: ISessionResponse;
6
6
  isJoined?: boolean | null;
7
+ onOpenThreadInfo?: () => void;
7
8
  }
8
9
  type SelectSessionValueType = SessionStatus | SessionTag;
9
10
  export interface SelectSessionOption {
@@ -13,6 +14,6 @@ export interface SelectSessionOption {
13
14
  tintColorClassnameBg: string;
14
15
  bgTintColorClassname: string;
15
16
  }
16
- declare const MessageHeader: ({ onClose, currentSession, isJoined, }: MessageHeaderProps) => import("react/jsx-runtime").JSX.Element;
17
+ declare const MessageHeader: ({ onClose, currentSession, isJoined, onOpenThreadInfo, }: MessageHeaderProps) => import("react/jsx-runtime").JSX.Element;
17
18
  export default MessageHeader;
18
19
  //# sourceMappingURL=MessageHeader.d.ts.map
@@ -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;AAM/C,UAAU,kBAAkB;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC3B;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,wCAIpB,kBAAkB,4CA6MpB,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;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"}
@@ -13,8 +13,9 @@ import { useUpdateSession } from "../../hooks/session/useUpdateSession";
13
13
  import useAuthStore from "../../store/auth";
14
14
  import SearchDrawer from "../../components/search-conversation/SearchDrawer";
15
15
  import { isGroupSession } from "../../utils/imCommon";
16
+ import { useGroupPermission } from "../../hooks/group/useGroupPermission";
16
17
  import GroupMembersDrawer from "./GroupMembersDrawer";
17
- const MessageHeader = ({ onClose, currentSession, isJoined, }) => {
18
+ const MessageHeader = ({ onClose, currentSession, isJoined, onOpenThreadInfo, }) => {
18
19
  var _a, _b;
19
20
  const { t } = useTranslation();
20
21
  const isCx = useAuthStore((state) => state.isCx);
@@ -22,6 +23,7 @@ const MessageHeader = ({ onClose, currentSession, isJoined, }) => {
22
23
  const conversationData = useConversationStore((state) => state.conversationData);
23
24
  const currentGroupInfo = useConversationStore((state) => state.currentGroupInfo);
24
25
  const { mutate: updateSession } = useUpdateSession();
26
+ const permissions = useGroupPermission(conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID);
25
27
  const { avatar, displayName } = useConversationDisplayData(conversationData);
26
28
  const shouldShowMemberCount = isGroupSession(conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationType);
27
29
  const [currentSessionStatus, setCurrentSessionStatus] = useState(SessionStatus.UNASSIGNED);
@@ -127,6 +129,9 @@ const MessageHeader = ({ onClose, currentSession, isJoined, }) => {
127
129
  setCurrentSessionStatus(currentSession.status);
128
130
  }
129
131
  }, [currentSession]);
130
- 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 && isJoined === true && isCrm && (_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", 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 }) }))] })] }));
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 }) }))] })] }));
131
136
  };
132
137
  export default MessageHeader;
@@ -4,6 +4,7 @@ interface MessageListProps {
4
4
  className?: string;
5
5
  onClose?: () => void;
6
6
  openCreateCannedModal?: () => void;
7
+ onOpenThreadInfo?: () => void;
7
8
  }
8
9
  declare const MessageList: (props: MessageListProps) => import("react/jsx-runtime").JSX.Element;
9
10
  export default MessageList;
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAyBA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CA0N3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AA2BA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAuO3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -19,13 +19,18 @@ import { useChatContext } from "../../context/ChatContext";
19
19
  import { useRevokeMessage } from "../../hooks/message/useRevokeMessage";
20
20
  import { useConversationSessionState } from "../../hooks/session/useConversationSessionState";
21
21
  import { useJoinGroupFlow } from "../../hooks/session/useJoinGroupFlow";
22
+ import { useGroupPermission } from "../../hooks/group/useGroupPermission";
23
+ import { isGroupSession } from "../../utils/imCommon";
22
24
  import { ConnectStatus, SessionStatus } from "../../types/chat";
23
25
  dayjs.extend(isToday);
24
26
  const MessageList = (props) => {
25
27
  const { t } = useTranslation();
26
28
  const { user, connectStatus } = useChatContext();
27
- const { onClose, conversationId, searchClientMsgID, openCreateCannedModal } = props;
29
+ const { onClose, conversationId, searchClientMsgID, openCreateCannedModal, onOpenThreadInfo, } = props;
28
30
  const conversationData = useConversationStore((state) => state.conversationData);
31
+ const permissions = useGroupPermission(conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID);
32
+ const isGroupChat = isGroupSession(conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationType);
33
+ const canSendMessage = !isGroupChat || permissions.sendMessage;
29
34
  const setQuotedMessage = useConversationStore((state) => state.setQuotedMessage);
30
35
  const setSearchClientMsgID = useConversationStore((state) => state.setSearchClientMsgID);
31
36
  const [openMenuId, setOpenMenuId] = useState(null);
@@ -102,6 +107,6 @@ const MessageList = (props) => {
102
107
  if (!conversationData) {
103
108
  return (_jsx("div", { className: "flex flex-1 items-center justify-center h-full", children: connectStatus !== ConnectStatus.Connected ? (_jsx(Spin, {})) : (_jsx(Empty, { description: t("no_conversation_data") })) }));
104
109
  }
105
- return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full min-w-0 bg-white", style: { overflowX: "hidden" }, children: [_jsx(MessageHeader, { onClose: onClose, currentSession: latestConversationSession, isJoined: isJoined }), _jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array, contextMenuOpen: openMenuId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenMenuId(open ? message.clientMsgID : null), onRevokeMessage: handleOpenRevoke, onQuoteMessage: setQuotedMessage, onPressQuoteMessage: onPressQuoteMessage }, message.clientMsgID))) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), isCheckingMembership ? (_jsx("div", { className: "border-t bg-white py-4 flex items-center justify-center", children: _jsx(Spin, {}) })) : (latestConversationSession === null || latestConversationSession === void 0 ? void 0 : latestConversationSession.status) === SessionStatus.UNASSIGNED ? (_jsx(UnassignedSessionFooter, { sessionId: latestConversationSession.id, teamId: latestConversationSession.teamId })) : shouldRestrictToLastSession ? (_jsxs("div", { className: "border-t bg-white py-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-sm text-gray-500", children: t("join_group_required") }), _jsx(Button, { type: "primary", onClick: joinGroup, loading: isJoining, children: t("join_group") })] })) : (_jsx(MessageFooter, { currentSession: latestConversationSession, openCreateCannedModal: openCreateCannedModal })), _jsx(Modal, { centered: true, open: showConfirmRevoke, onOk: onRevokeMessage, onCancel: handleCloseRevoke, title: t("revoke_message_confirm_title"), okText: t("revoke"), cancelText: t("cancel"), okType: "danger", confirmLoading: isRevoking, getContainer: false, forceRender: true, children: _jsx("p", { children: t("revoke_message_confirm_message") }) })] }));
110
+ return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full min-w-0 bg-white", style: { overflowX: "hidden" }, children: [_jsx(MessageHeader, { onClose: onClose, currentSession: latestConversationSession, isJoined: isJoined, onOpenThreadInfo: onOpenThreadInfo }), _jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array, contextMenuOpen: openMenuId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenMenuId(open ? message.clientMsgID : null), onRevokeMessage: handleOpenRevoke, onQuoteMessage: setQuotedMessage, onPressQuoteMessage: onPressQuoteMessage }, message.clientMsgID))) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), isCheckingMembership ? (_jsx("div", { className: "border-t bg-white py-4 flex items-center justify-center", children: _jsx(Spin, {}) })) : (latestConversationSession === null || latestConversationSession === void 0 ? void 0 : latestConversationSession.status) === SessionStatus.UNASSIGNED ? (_jsx(UnassignedSessionFooter, { sessionId: latestConversationSession.id, teamId: latestConversationSession.teamId })) : shouldRestrictToLastSession ? (_jsxs("div", { className: "border-t bg-white py-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-sm text-gray-500", children: t("join_group_required") }), _jsx(Button, { type: "primary", onClick: joinGroup, loading: isJoining, children: t("join_group") })] })) : !canSendMessage ? (_jsx("div", { className: "border-t bg-[#f5f5f5] py-3 flex items-center justify-center", children: _jsx("p", { className: "text-sm text-gray-500", children: t("send_message_disabled") }) })) : (_jsx(MessageFooter, { currentSession: latestConversationSession, openCreateCannedModal: openCreateCannedModal })), _jsx(Modal, { centered: true, open: showConfirmRevoke, onOk: onRevokeMessage, onCancel: handleCloseRevoke, title: t("revoke_message_confirm_title"), okText: t("revoke"), cancelText: t("cancel"), okType: "danger", confirmLoading: isRevoking, getContainer: false, forceRender: true, children: _jsx("p", { children: t("revoke_message_confirm_message") }) })] }));
106
111
  };
107
112
  export default MessageList;
@@ -1 +1 @@
1
- {"version":3,"file":"SelectSession.d.ts","sourceRoot":"","sources":["../../../src/components/message/SelectSession.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,UAAU,kBAAkB;IAC1B,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IACxD,cAAc,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,QAAA,MAAM,aAAa,GAAI,4DAMpB,kBAAkB,4CAwDpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"SelectSession.d.ts","sourceRoot":"","sources":["../../../src/components/message/SelectSession.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,UAAU,kBAAkB;IAC1B,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IACxD,cAAc,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,QAAA,MAAM,aAAa,GAAI,4DAMpB,kBAAkB,4CAmEpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -5,7 +5,7 @@ import { Icon } from "../../components/icon";
5
5
  import clsx from "clsx";
6
6
  const SelectSession = ({ options, value, onChange, excludeOptions, placeholder, }) => {
7
7
  const selectedOption = options.find((option) => option.value === value);
8
- const renderOptionLabel = (option) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: clsx("w-2 h-2 rounded-full", option.tintColorClassnameBg) }), _jsx("span", { className: clsx("text-xs truncate flex-1", option.tintColorClassname), children: option.label })] }));
8
+ const renderOptionLabel = (option, truncateLabel = false) => (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: clsx("w-2 h-2 rounded-full shrink-0", option.tintColorClassnameBg) }), _jsx("span", { className: clsx("text-xs whitespace-nowrap", truncateLabel && "truncate", option.tintColorClassname), children: option.label })] }));
9
9
  const filteredOptions = options.filter((option) => option.value === value || !(excludeOptions === null || excludeOptions === void 0 ? void 0 : excludeOptions.includes(option.value)));
10
10
  const selectOptions = filteredOptions.map((option) => ({
11
11
  label: renderOptionLabel(option),
@@ -14,10 +14,10 @@ const SelectSession = ({ options, value, onChange, excludeOptions, placeholder,
14
14
  const handleSelect = (val) => {
15
15
  onChange(val);
16
16
  };
17
- return (_jsx("div", { className: "relative", children: _jsx(Select, { className: `${selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.bgTintColorClassname} custom-select min-w-[100px]`, placement: "bottomLeft", placeholder: placeholder, options: selectOptions, value: selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value, onSelect: handleSelect, suffixIcon: _jsx(Icon, { icon: "angle-down-o", className: `${selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.tintColorClassname} mt-[2px]`, size: 14 }), menuItemSelectedIcon: null, labelRender: () => ["NONE", ""].includes(selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value)
17
+ return (_jsx("div", { className: "relative shrink-0", children: _jsx(Select, { className: `${selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.bgTintColorClassname} custom-select min-w-[100px]`, placement: "bottomLeft", placeholder: placeholder, options: selectOptions, value: selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value, onSelect: handleSelect, popupMatchSelectWidth: false, suffixIcon: _jsx(Icon, { icon: "angle-down-o", className: `${selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.tintColorClassname} mt-[2px]`, size: 14 }), menuItemSelectedIcon: null, labelRender: () => ["NONE", ""].includes(selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value)
18
18
  ? placeholder
19
19
  : selectedOption
20
- ? renderOptionLabel(selectedOption)
20
+ ? renderOptionLabel(selectedOption, true)
21
21
  : undefined }) }));
22
22
  };
23
23
  export default SelectSession;
@@ -7,7 +7,7 @@ import { useGetTeamSessionSummary } from "../../hooks/session/useGetTeamSessionS
7
7
  import useSessionStore from "../../store/session";
8
8
  import emitter from "../../utils/events";
9
9
  import SessionFilterMenu from "./SessionFilterMenu";
10
- const TeamGroup = memo(({ team, isExpanded, isSelected, selectedFilter, onToggle, onFilterSelect, }) => (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-2 cursor-pointer hover:bg-gray-50", onClick: onToggle, children: [_jsx("span", { className: "text-sm font-semibold text-blue-500 truncate flex-1", children: team.teamName }), _jsx(Icon, { icon: isExpanded ? "angle-up-o" : "angle-down-o", size: 16, className: "text-gray-400 shrink-0" })] }), isExpanded && (_jsx(SessionFilterMenu, { summary: team.summary, isActive: isSelected, filterSummary: selectedFilter, onFilterSelect: onFilterSelect, includeUnassigned: true, activeCount: team.summary.activeSessionCount }))] })));
10
+ const TeamGroup = memo(({ team, isExpanded, isSelected, selectedFilter, onToggle, onFilterSelect, }) => (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-2 cursor-pointer hover:bg-[#f5f5f5]", onClick: onToggle, children: [_jsx("span", { className: "text-sm font-semibold text-blue-500 truncate flex-1", children: team.teamName }), _jsx(Icon, { icon: isExpanded ? "angle-up-o" : "angle-down-o", size: 16, className: "text-gray-400 shrink-0" })] }), isExpanded && (_jsx(SessionFilterMenu, { summary: team.summary, isActive: isSelected, filterSummary: selectedFilter, onFilterSelect: onFilterSelect, includeUnassigned: true, activeCount: team.summary.activeSessionCount }))] })));
11
11
  const DeskTeamInbox = () => {
12
12
  const { t } = useTranslation();
13
13
  const { data: teamSummaries, refetch } = useGetTeamSessionSummary();
@@ -0,0 +1,11 @@
1
+ export interface GroupThreadInfoConfig {
2
+ showAllowSendMessage?: boolean;
3
+ showMutedChatList?: boolean;
4
+ }
5
+ interface GroupThreadInfoProps {
6
+ onClose?: () => void;
7
+ config?: GroupThreadInfoConfig;
8
+ }
9
+ declare const GroupThreadInfo: ({ onClose, config }: GroupThreadInfoProps) => import("react/jsx-runtime").JSX.Element | null;
10
+ export default GroupThreadInfo;
11
+ //# sourceMappingURL=GroupThreadInfo.d.ts.map
@@ -0,0 +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"}