@droppii-org/chat-sdk 0.2.1 → 0.3.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 (67) hide show
  1. package/dist/components/conversation/ConversationByGroupItem.d.ts +5 -3
  2. package/dist/components/conversation/ConversationByGroupItem.d.ts.map +1 -1
  3. package/dist/components/conversation/ConversationByGroupItem.js +24 -35
  4. package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
  5. package/dist/components/conversation/DeskConversationList.js +4 -3
  6. package/dist/components/conversation-detail/ConversationMessageList.d.ts.map +1 -1
  7. package/dist/components/conversation-detail/ConversationMessageList.js +4 -1
  8. package/dist/components/group/AddMemberModal.d.ts +1 -2
  9. package/dist/components/group/AddMemberModal.d.ts.map +1 -1
  10. package/dist/components/group/AddMemberModal.js +2 -2
  11. package/dist/components/group/GroupCompositeAvatar.d.ts +11 -0
  12. package/dist/components/group/GroupCompositeAvatar.d.ts.map +1 -0
  13. package/dist/components/group/GroupCompositeAvatar.js +40 -0
  14. package/dist/components/message/GroupMembersDrawer.d.ts.map +1 -1
  15. package/dist/components/message/GroupMembersDrawer.js +22 -15
  16. package/dist/components/message/MessageHeader.d.ts.map +1 -1
  17. package/dist/components/message/MessageHeader.js +2 -1
  18. package/dist/components/message/MessageList.d.ts.map +1 -1
  19. package/dist/components/message/MessageList.js +31 -2
  20. package/dist/components/thread/GroupThreadInfo.d.ts.map +1 -1
  21. package/dist/components/thread/GroupThreadInfo.js +4 -3
  22. package/dist/constants/im.d.ts +13 -0
  23. package/dist/constants/im.d.ts.map +1 -1
  24. package/dist/constants/im.js +16 -0
  25. package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
  26. package/dist/hooks/global/useGlobalEvent.js +10 -2
  27. package/dist/hooks/group/useConversationGroups.d.ts +20 -0
  28. package/dist/hooks/group/useConversationGroups.d.ts.map +1 -0
  29. package/dist/hooks/group/useConversationGroups.js +116 -0
  30. package/dist/hooks/group/useCreateGroup.d.ts.map +1 -1
  31. package/dist/hooks/group/useCreateGroup.js +38 -7
  32. package/dist/hooks/group/useEligibleAccountsForGroup.d.ts +1 -1
  33. package/dist/hooks/group/useEligibleAccountsForGroup.d.ts.map +1 -1
  34. package/dist/hooks/group/useEligibleAccountsForGroup.js +6 -9
  35. package/dist/hooks/group/useGetGroupCandidates.d.ts +2 -1
  36. package/dist/hooks/group/useGetGroupCandidates.d.ts.map +1 -1
  37. package/dist/hooks/group/useGetGroupCandidates.js +3 -2
  38. package/dist/hooks/group/useGroupMemberActions.d.ts +6 -0
  39. package/dist/hooks/group/useGroupMemberActions.d.ts.map +1 -1
  40. package/dist/hooks/group/useGroupMemberActions.js +12 -0
  41. package/dist/hooks/group/useGroupPermission.d.ts +3 -1
  42. package/dist/hooks/group/useGroupPermission.d.ts.map +1 -1
  43. package/dist/hooks/group/useGroupPermission.js +33 -37
  44. package/dist/hooks/session/useSessionLatestPreview.d.ts +6 -2
  45. package/dist/hooks/session/useSessionLatestPreview.d.ts.map +1 -1
  46. package/dist/locales/vi/common.json +14 -0
  47. package/dist/services/query.d.ts +1 -1
  48. package/dist/services/query.js +1 -1
  49. package/dist/services/routes.d.ts +1 -0
  50. package/dist/services/routes.d.ts.map +1 -1
  51. package/dist/services/routes.js +1 -0
  52. package/dist/store/conversation.d.ts.map +1 -1
  53. package/dist/store/conversation.js +25 -1
  54. package/dist/store/type.d.ts +1 -0
  55. package/dist/store/type.d.ts.map +1 -1
  56. package/dist/styles/global.css +1 -1
  57. package/dist/types/dto.d.ts +8 -0
  58. package/dist/types/dto.d.ts.map +1 -1
  59. package/dist/utils/common.d.ts.map +1 -1
  60. package/dist/utils/common.js +20 -2
  61. package/dist/utils/messageLog.d.ts +4 -0
  62. package/dist/utils/messageLog.d.ts.map +1 -1
  63. package/dist/utils/messageLog.js +113 -0
  64. package/package.json +2 -2
  65. package/dist/hooks/group/useJoinedGroups.d.ts +0 -13
  66. package/dist/hooks/group/useJoinedGroups.d.ts.map +0 -1
  67. package/dist/hooks/group/useJoinedGroups.js +0 -33
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from "react";
3
- import { Avatar, Input, Modal, Switch, message } from "antd";
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";
@@ -14,8 +14,9 @@ import { useDismissGroup } from "../../hooks/group/useDismissGroup";
14
14
  import { useGroupPermission } from "../../hooks/group/useGroupPermission";
15
15
  import AdminPermissionModal from "../../components/group/AdminPermissionModal";
16
16
  import MemberPermissionPanel from "../../components/group/MemberPermissionPanel";
17
+ import GroupCompositeAvatar from "../../components/group/GroupCompositeAvatar";
17
18
  const GroupThreadInfo = ({ onClose, config }) => {
18
- var _a, _b, _c, _d, _e;
19
+ var _a, _b, _c;
19
20
  const { t } = useTranslation();
20
21
  const conversationData = useConversationStore((state) => state.conversationData);
21
22
  const currentGroupInfo = useConversationStore((state) => state.currentGroupInfo);
@@ -151,6 +152,6 @@ const GroupThreadInfo = ({ onClose, config }) => {
151
152
  if (!groupID) {
152
153
  return null;
153
154
  }
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") }) }))] }));
155
+ 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 }), 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() === ((_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, 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") }) }))] }));
155
156
  };
156
157
  export default GroupThreadInfo;
@@ -1,3 +1,16 @@
1
1
  import { SessionType } from "@droppii-org/wasm-client-sdk";
2
2
  export declare const GroupSessionTypes: SessionType[];
3
+ export declare const GROUP_PERMISSION_KEY: {
4
+ readonly sendMessage: "SEND_MESSAGE";
5
+ readonly pinMessage: "PIN_MESSAGE";
6
+ readonly updateGroupName: "UPDATE_GROUP_NAME";
7
+ readonly updateGroupAvatar: "UPDATE_GROUP_AVATAR";
8
+ readonly updateGroupDescription: "UPDATE_GROUP_DESCRIPTION";
9
+ readonly addMember: "ADD_MEMBER";
10
+ readonly removeMember: "REMOVE_MEMBER";
11
+ readonly addAdmin: "ADD_ADMIN";
12
+ readonly transferOwnership: "TRANSFER_OWNERSHIP";
13
+ readonly configGroupPermission: "CONFIG_GROUP_PERMISSION";
14
+ readonly viewMemberInformation: "VIEW_MEMBER_INFORMATION";
15
+ };
3
16
  //# sourceMappingURL=im.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"im.d.ts","sourceRoot":"","sources":["../../src/constants/im.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAE3D,eAAO,MAAM,iBAAiB,eAAgD,CAAC"}
1
+ {"version":3,"file":"im.d.ts","sourceRoot":"","sources":["../../src/constants/im.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAE3D,eAAO,MAAM,iBAAiB,eAAgD,CAAC;AAK/E,eAAO,MAAM,oBAAoB;;;;;;;;;;;;CAYvB,CAAC"}
@@ -1,2 +1,18 @@
1
1
  import { SessionType } from "@droppii-org/wasm-client-sdk";
2
2
  export const GroupSessionTypes = [SessionType.Group, SessionType.WorkingGroup];
3
+ // Raw permission strings BE returns in SelfUserInfo.permissions /
4
+ // GroupMemberItem.permissions (DROPPII-30247). Keys match the Go constants
5
+ // (permission.SendMessage, etc) — see DROPPII-30248 BE update.
6
+ export const GROUP_PERMISSION_KEY = {
7
+ sendMessage: "SEND_MESSAGE",
8
+ pinMessage: "PIN_MESSAGE",
9
+ updateGroupName: "UPDATE_GROUP_NAME",
10
+ updateGroupAvatar: "UPDATE_GROUP_AVATAR",
11
+ updateGroupDescription: "UPDATE_GROUP_DESCRIPTION",
12
+ addMember: "ADD_MEMBER",
13
+ removeMember: "REMOVE_MEMBER",
14
+ addAdmin: "ADD_ADMIN",
15
+ transferOwnership: "TRANSFER_OWNERSHIP",
16
+ configGroupPermission: "CONFIG_GROUP_PERMISSION",
17
+ viewMemberInformation: "VIEW_MEMBER_INFORMATION",
18
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"useGlobalEvent.d.ts","sourceRoot":"","sources":["../../../src/hooks/global/useGlobalEvent.ts"],"names":[],"mappings":"AAuCA,eAAO,MAAM,cAAc,YAqY1B,CAAC"}
1
+ {"version":3,"file":"useGlobalEvent.d.ts","sourceRoot":"","sources":["../../../src/hooks/global/useGlobalEvent.ts"],"names":[],"mappings":"AAuCA,eAAO,MAAM,cAAc,YA8Y1B,CAAC"}
@@ -26,7 +26,7 @@ export const useGlobalEvent = () => {
26
26
  const updateConversationList = useConversationStore((state) => state.updateConversationList);
27
27
  const getConversationListByReq = useConversationStore((state) => state.getConversationListByReq);
28
28
  const getCurrentGroupInfoByReq = useConversationStore((state) => state.getCurrentGroupInfoByReq);
29
- const getCurrentMemberInGroupByReq = useConversationStore((state) => state.getCurrentMemberInGroupByReq);
29
+ const getSelfGroupPermissionByReq = useConversationStore((state) => state.getSelfGroupPermissionByReq);
30
30
  const { mutate: refetchChatToken } = useRefetchChatToken();
31
31
  const accessToken = useAuthStore((state) => state.accessToken);
32
32
  const chatToken = useAuthStore((state) => state.chatToken);
@@ -42,7 +42,7 @@ export const useGlobalEvent = () => {
42
42
  }
43
43
  await Promise.all([
44
44
  getCurrentGroupInfoByReq(currentConversation.groupID),
45
- getCurrentMemberInGroupByReq(currentConversation.groupID),
45
+ getSelfGroupPermissionByReq(currentConversation.groupID),
46
46
  ]);
47
47
  };
48
48
  const revokedMessageHandler = ({ data }) => {
@@ -204,6 +204,12 @@ export const useGlobalEvent = () => {
204
204
  const groupInfoChangedHandler = () => {
205
205
  void refreshCurrentGroupState();
206
206
  };
207
+ // BE pushes this when a member's role/permissions change (DROPPII-30248
208
+ // spec: actions must always check the LATEST permissions, not stale UI) —
209
+ // refetch so useGroupPermission picks up the new permissions[] right away.
210
+ const groupMemberInfoChangedHandler = () => {
211
+ void refreshCurrentGroupState();
212
+ };
207
213
  const groupDismissedHandler = ({ data }) => {
208
214
  const currentConversation = useConversationStore.getState().currentConversation;
209
215
  if ((currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.groupID) === data.groupID) {
@@ -251,6 +257,7 @@ export const useGlobalEvent = () => {
251
257
  DChatSDK.on(CbEvents.OnJoinedGroupAdded, joinedGroupAddedHandler);
252
258
  // group info
253
259
  DChatSDK.on(CbEvents.OnGroupInfoChanged, groupInfoChangedHandler);
260
+ DChatSDK.on(CbEvents.OnGroupMemberInfoChanged, groupMemberInfoChangedHandler);
254
261
  DChatSDK.on(CbEvents.OnGroupDismissed, groupDismissedHandler);
255
262
  // black list
256
263
  DChatSDK.on(CbEvents.OnBlackAdded, blackListChangedHandler);
@@ -283,6 +290,7 @@ export const useGlobalEvent = () => {
283
290
  DChatSDK.off(CbEvents.OnJoinedGroupAdded, joinedGroupAddedHandler);
284
291
  // group info
285
292
  DChatSDK.off(CbEvents.OnGroupInfoChanged, groupInfoChangedHandler);
293
+ DChatSDK.off(CbEvents.OnGroupMemberInfoChanged, groupMemberInfoChangedHandler);
286
294
  DChatSDK.off(CbEvents.OnGroupDismissed, groupDismissedHandler);
287
295
  // black list
288
296
  DChatSDK.off(CbEvents.OnBlackAdded, blackListChangedHandler);
@@ -0,0 +1,20 @@
1
+ import { ConversationItem } from "@droppii-org/wasm-client-sdk";
2
+ import { BaseResponse, IConversationGroupItem } from "../../types/dto";
3
+ interface UseConversationGroupsParams {
4
+ enabled?: boolean;
5
+ pageSize?: number;
6
+ }
7
+ export interface ConversationGroupDisplayItem {
8
+ groupId: string;
9
+ conversationId: string;
10
+ conversation: ConversationItem;
11
+ }
12
+ export declare const useConversationGroups: ({ enabled, pageSize, }?: UseConversationGroupsParams) => {
13
+ groups: ConversationGroupDisplayItem[];
14
+ fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<BaseResponse<IConversationGroupItem[]>, unknown>, Error>>;
15
+ hasNextPage: boolean;
16
+ isFetchingNextPage: boolean;
17
+ isLoading: boolean;
18
+ };
19
+ export {};
20
+ //# sourceMappingURL=useConversationGroups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useConversationGroups.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useConversationGroups.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAe,MAAM,8BAA8B,CAAC;AAK7E,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAKnE,UAAU,2BAA2B;IACnC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,gBAAgB,CAAC;CAChC;AAiED,eAAO,MAAM,qBAAqB,GAAI,yBAGnC,2BAAgC;;;;;;CAoElC,CAAC"}
@@ -0,0 +1,116 @@
1
+ "use client";
2
+ import { useMemo } from "react";
3
+ import { useInfiniteQuery } from "@tanstack/react-query";
4
+ import { SessionType } from "@droppii-org/wasm-client-sdk";
5
+ import { apiInstance } from "../../services/api";
6
+ import { ENDPOINTS } from "../../services/routes";
7
+ import { QUERY_KEYS } from "../../services/query";
8
+ import { PAGE_SIZE } from "../../constants";
9
+ import useAuthStore from "../../store/auth";
10
+ import useConversationStore from "../../store/conversation";
11
+ import { DChatSDK } from "../../constants/sdk";
12
+ // Placeholder used until the store has synced the real ConversationItem for
13
+ // a brand new group (e.g. right after create-group, or first time this list
14
+ // loads) — carries just enough for ConversationByGroupItem to render
15
+ // something instead of the row disappearing while the sync is in flight.
16
+ const buildFallbackConversation = (group) => ({
17
+ conversationID: group.conversationId,
18
+ conversationType: SessionType.Group,
19
+ userID: "",
20
+ groupID: group.groupId,
21
+ showName: group.groupName,
22
+ faceURL: group.groupAvatar || "",
23
+ recvMsgOpt: 0,
24
+ unreadCount: 0,
25
+ groupAtType: 0,
26
+ latestMsg: "",
27
+ latestMsgSendTime: group.latestMessageAt
28
+ ? new Date(group.latestMessageAt).getTime()
29
+ : 0,
30
+ draftText: "",
31
+ draftTextTime: 0,
32
+ burnDuration: 0,
33
+ maxSeq: 0,
34
+ minSeq: 0,
35
+ msgDestructTime: 0,
36
+ isPinned: false,
37
+ isNotInGroup: false,
38
+ isPrivateChat: false,
39
+ isMsgDestruct: false,
40
+ attachedInfo: "",
41
+ });
42
+ // Same join pattern as useGetSession: the REST endpoint only returns group
43
+ // metadata (no latestMsg) — sync each group's full ConversationItem (which
44
+ // carries latestMsg/latestMsgSendTime/unreadCount) into the shared
45
+ // conversationList store via the SDK, then join on conversationId.
46
+ const syncGroupConversationsToStore = async (groups) => {
47
+ const currentList = useConversationStore.getState().conversationList;
48
+ const newGroups = groups.filter((group) => !currentList.some((conversation) => conversation.conversationID === group.conversationId));
49
+ if (!newGroups.length)
50
+ return;
51
+ try {
52
+ const { data } = await DChatSDK.getMultipleConversation(newGroups.map((group) => group.conversationId));
53
+ if (data === null || data === void 0 ? void 0 : data.length) {
54
+ useConversationStore.getState().updateConversationList(data, "filter");
55
+ }
56
+ }
57
+ catch (error) {
58
+ console.error("syncGroupConversationsToStore", error);
59
+ }
60
+ };
61
+ export const useConversationGroups = ({ enabled = true, pageSize = PAGE_SIZE.medium, } = {}) => {
62
+ const conversationList = useConversationStore((state) => state.conversationList);
63
+ const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } = useInfiniteQuery({
64
+ initialPageParam: 1,
65
+ queryKey: [QUERY_KEYS.GET_CONVERSATION_GROUPS, pageSize],
66
+ queryFn: async ({ pageParam = 1 }) => {
67
+ var _a, _b;
68
+ const applicationType = useAuthStore.getState().applicationType;
69
+ const res = await apiInstance.get(ENDPOINTS.chatService.getConversationGroups, {
70
+ params: {
71
+ page: pageParam,
72
+ pageSize,
73
+ applicationType,
74
+ },
75
+ });
76
+ if ((_b = (_a = res === null || res === void 0 ? void 0 : res.data) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.length) {
77
+ void syncGroupConversationsToStore(res.data.data).catch((error) => {
78
+ console.error("syncGroupConversationsToStore", error);
79
+ });
80
+ }
81
+ return res.data;
82
+ },
83
+ getNextPageParam: (lastPage) => {
84
+ var _a, _b;
85
+ const dataLength = ((_a = lastPage === null || lastPage === void 0 ? void 0 : lastPage.data) === null || _a === void 0 ? void 0 : _a.length) || 0;
86
+ const currentPage = ((_b = lastPage === null || lastPage === void 0 ? void 0 : lastPage.pageable) === null || _b === void 0 ? void 0 : _b.pageNumber) || 1;
87
+ return dataLength < pageSize ? undefined : currentPage + 1;
88
+ },
89
+ enabled,
90
+ });
91
+ const groups = useMemo(() => {
92
+ if (!data)
93
+ return [];
94
+ // Render straight from the REST response — the list must show every
95
+ // group the API returned immediately, even before syncGroupConversationsToStore
96
+ // (async) has had a chance to populate conversationList. Use the synced
97
+ // ConversationItem when available (real latestMsg/unreadCount), else a
98
+ // fallback built from the REST fields so the row never disappears.
99
+ const allItems = data.pages.flatMap((page) => page.data);
100
+ return allItems.map((group) => {
101
+ const syncedConversation = conversationList === null || conversationList === void 0 ? void 0 : conversationList.find((conversation) => conversation.conversationID === group.conversationId);
102
+ return {
103
+ groupId: group.groupId,
104
+ conversationId: group.conversationId,
105
+ conversation: syncedConversation !== null && syncedConversation !== void 0 ? syncedConversation : buildFallbackConversation(group),
106
+ };
107
+ });
108
+ }, [data, conversationList]);
109
+ return {
110
+ groups,
111
+ fetchNextPage,
112
+ hasNextPage,
113
+ isFetchingNextPage,
114
+ isLoading,
115
+ };
116
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"useCreateGroup.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useCreateGroup.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAIjE,UAAU,iBAAiB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAOD,eAAO,MAAM,cAAc;6DAO2B,iBAAiB;CAoDtE,CAAC"}
1
+ {"version":3,"file":"useCreateGroup.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useCreateGroup.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,UAAU,iBAAiB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAqCD,eAAO,MAAM,cAAc;6DAQ2B,iBAAiB;CAyDtE,CAAC"}
@@ -1,13 +1,40 @@
1
1
  "use client";
2
2
  import { useCallback } from "react";
3
3
  import { useRouter } from "next/navigation";
4
+ import { useQueryClient } from "@tanstack/react-query";
4
5
  import { message } from "antd";
5
6
  import { useTranslation } from "react-i18next";
6
7
  import { GroupType, GroupVerificationType, GroupVisibility, SessionType } from "@droppii-org/wasm-client-sdk";
7
8
  import { DChatSDK } from "../../constants/sdk";
8
9
  import useAuthStore from "../../store/auth";
9
10
  import { generateDefaultGroupName } from "../../utils/groupName";
10
- const DEFAULT_GROUP_FACE_URL = "/droppii.jpeg";
11
+ import { QUERY_KEYS } from "../../services/query";
12
+ const GET_CONVERSATION_RETRY_COUNT = 4;
13
+ const GET_CONVERSATION_RETRY_DELAY_MS = 500;
14
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
15
+ // createGroup()'s own response succeeding doesn't mean the local WASM store
16
+ // has the new conversation yet — the WS event that inserts it locally can
17
+ // arrive after an unspecified delay (same reasoning as
18
+ // useGlobalEvent.ts's joinedGroupAddedHandler). Retry briefly instead of
19
+ // surfacing "create group failed" for a group that was, in fact, created.
20
+ const getOneConversationWithRetry = async (groupID) => {
21
+ let lastError;
22
+ for (let attempt = 0; attempt < GET_CONVERSATION_RETRY_COUNT; attempt++) {
23
+ try {
24
+ return await DChatSDK.getOneConversation({
25
+ sourceID: groupID,
26
+ sessionType: SessionType.Group,
27
+ });
28
+ }
29
+ catch (error) {
30
+ lastError = error;
31
+ if (attempt < GET_CONVERSATION_RETRY_COUNT - 1) {
32
+ await delay(GET_CONVERSATION_RETRY_DELAY_MS);
33
+ }
34
+ }
35
+ }
36
+ throw lastError;
37
+ };
11
38
  // Q4 (non-block): calling DChatSDK.createGroup() directly — the SDK's own
12
39
  // eligibility check at submission time (if any) is whatever openIM does
13
40
  // server-side; there's no separate BE revalidation endpoint yet. If members
@@ -17,6 +44,7 @@ export const useCreateGroup = () => {
17
44
  const { t } = useTranslation("conversation-inbox");
18
45
  const { t: tCommon } = useTranslation();
19
46
  const router = useRouter();
47
+ const queryClient = useQueryClient();
20
48
  const userID = useAuthStore((state) => state.userID);
21
49
  const createGroup = useCallback(async ({ groupName, isPublic, members, faceURL }) => {
22
50
  var _a, _b;
@@ -28,7 +56,10 @@ export const useCreateGroup = () => {
28
56
  firstMemberName: firstMember === null || firstMember === void 0 ? void 0 : firstMember.displayName,
29
57
  remainingCount: restMembers.length,
30
58
  });
31
- const resolvedFaceURL = faceURL || (firstMember === null || firstMember === void 0 ? void 0 : firstMember.avatar) || DEFAULT_GROUP_FACE_URL;
59
+ // AC-Default2: no picked avatar leave faceURL empty. UI renders a
60
+ // composite of the owner's + first-joined member's avatars instead of
61
+ // a static placeholder (see GroupCompositeAvatar).
62
+ const resolvedFaceURL = faceURL || "";
32
63
  try {
33
64
  const { data: group } = await DChatSDK.createGroup({
34
65
  memberUserIDs: members.map((member) => member.userID),
@@ -42,11 +73,11 @@ export const useCreateGroup = () => {
42
73
  visibility: isPublic ? GroupVisibility.Public : GroupVisibility.Private,
43
74
  },
44
75
  });
45
- const { data: conversation } = await DChatSDK.getOneConversation({
46
- sourceID: group.groupID,
47
- sessionType: SessionType.Group,
48
- });
76
+ const { data: conversation } = await getOneConversationWithRetry(group.groupID);
49
77
  message.success(t("create_group.create_group_success"));
78
+ void queryClient.invalidateQueries({
79
+ queryKey: [QUERY_KEYS.GET_CONVERSATION_GROUPS],
80
+ });
50
81
  const searchParams = new URLSearchParams();
51
82
  searchParams.set("threadId", conversation.conversationID);
52
83
  router.push(`/chat?${searchParams.toString()}`);
@@ -57,6 +88,6 @@ export const useCreateGroup = () => {
57
88
  message.error(errorMessage);
58
89
  throw error;
59
90
  }
60
- }, [router, t, tCommon, userID]);
91
+ }, [router, t, tCommon, userID, queryClient]);
61
92
  return { createGroup };
62
93
  };
@@ -1,5 +1,5 @@
1
1
  import type { EligibleAccountItem } from "./useEligibleAccounts";
2
- export declare const useEligibleAccountsForGroup: (search: string, existingMemberIDs: string[], enabled?: boolean) => {
2
+ export declare const useEligibleAccountsForGroup: (search: string, groupID: string, enabled?: boolean) => {
3
3
  accounts: EligibleAccountItem[];
4
4
  isLoading: boolean;
5
5
  fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("../../types/dto").BaseResponse<import("../../types/dto").IGroupCandidateResponse[]>, unknown>, Error>>;
@@ -1 +1 @@
1
- {"version":3,"file":"useEligibleAccountsForGroup.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useEligibleAccountsForGroup.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAKjE,eAAO,MAAM,2BAA2B,GACtC,QAAQ,MAAM,EACd,mBAAmB,MAAM,EAAE,EAC3B,iBAAc;;;;;;CAgCf,CAAC"}
1
+ {"version":3,"file":"useEligibleAccountsForGroup.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useEligibleAccountsForGroup.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAIjE,eAAO,MAAM,2BAA2B,GACtC,QAAQ,MAAM,EACd,SAAS,MAAM,EACf,iBAAc;;;;;;CA0Bf,CAAC"}
@@ -1,21 +1,18 @@
1
1
  import { useMemo } from "react";
2
2
  import { useGetGroupCandidates } from "./useGetGroupCandidates";
3
- // getGroupCandidates has no server-side "exclude group members" filter yet
4
- // (BE gap tracked in DROPPII-30003 breakdown, Q1) — filtering existing group
5
- // members out client-side here as an interim until BE adds it.
6
- export const useEligibleAccountsForGroup = (search, existingMemberIDs, enabled = true) => {
3
+ // Server excludes accounts already in groupID from the candidate list
4
+ // (DROPPII-30248 BE update) — no client-side filtering needed anymore.
5
+ export const useEligibleAccountsForGroup = (search, groupID, enabled = true) => {
7
6
  const { candidates, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } = useGetGroupCandidates({
8
7
  searchTerm: search.trim(),
8
+ groupID,
9
9
  enabled,
10
10
  });
11
- const existingMemberIDSet = useMemo(() => new Set(existingMemberIDs), [existingMemberIDs]);
12
- const accounts = useMemo(() => candidates
13
- .filter((candidate) => !existingMemberIDSet.has(candidate.id))
14
- .map((candidate) => ({
11
+ const accounts = useMemo(() => candidates.map((candidate) => ({
15
12
  userID: candidate.id,
16
13
  displayName: candidate.fullName,
17
14
  avatar: candidate.avatar,
18
- })), [candidates, existingMemberIDSet]);
15
+ })), [candidates]);
19
16
  return {
20
17
  accounts,
21
18
  isLoading,
@@ -1,9 +1,10 @@
1
1
  import { BaseResponse, IGroupCandidateResponse } from "../../types/dto";
2
2
  interface UseGetGroupCandidatesParams {
3
3
  searchTerm?: string;
4
+ groupID?: string;
4
5
  enabled?: boolean;
5
6
  }
6
- export declare const useGetGroupCandidates: ({ searchTerm, enabled, }: UseGetGroupCandidatesParams) => {
7
+ export declare const useGetGroupCandidates: ({ searchTerm, groupID, enabled, }: UseGetGroupCandidatesParams) => {
7
8
  candidates: IGroupCandidateResponse[];
8
9
  fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<BaseResponse<IGroupCandidateResponse[]>, unknown>, Error>>;
9
10
  hasNextPage: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"useGetGroupCandidates.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useGetGroupCandidates.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAIpE,UAAU,2BAA2B;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,qBAAqB,GAAI,0BAGnC,2BAA2B;;;;;;CAqC7B,CAAC"}
1
+ {"version":3,"file":"useGetGroupCandidates.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useGetGroupCandidates.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAIpE,UAAU,2BAA2B;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IAIpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,qBAAqB,GAAI,mCAInC,2BAA2B;;;;;;CAsC7B,CAAC"}
@@ -4,16 +4,17 @@ import { QUERY_KEYS } from "../../services/query";
4
4
  import { apiInstance } from "../../services/api";
5
5
  import { ENDPOINTS } from "../../services/routes";
6
6
  const GROUP_CANDIDATES_PAGE_SIZE = 20;
7
- export const useGetGroupCandidates = ({ searchTerm = "", enabled = true, }) => {
7
+ export const useGetGroupCandidates = ({ searchTerm = "", groupID, enabled = true, }) => {
8
8
  const { data, fetchNextPage, hasNextPage, isFetchingNextPage, isLoading } = useInfiniteQuery({
9
9
  initialPageParam: 1,
10
- queryKey: [QUERY_KEYS.GET_GROUP_CANDIDATES, searchTerm],
10
+ queryKey: [QUERY_KEYS.GET_GROUP_CANDIDATES, searchTerm, groupID],
11
11
  queryFn: async ({ pageParam = 1 }) => {
12
12
  const res = await apiInstance.get(ENDPOINTS.chatService.getGroupCandidates, {
13
13
  params: {
14
14
  page: pageParam,
15
15
  pageSize: GROUP_CANDIDATES_PAGE_SIZE,
16
16
  searchTerm: searchTerm || undefined,
17
+ groupId: groupID || undefined,
17
18
  },
18
19
  });
19
20
  return res === null || res === void 0 ? void 0 : res.data;
@@ -21,5 +21,11 @@ interface TransferGroupOwnerParams {
21
21
  newOwnerUserID: string;
22
22
  }
23
23
  export declare const useTransferGroupOwner: () => import("@tanstack/react-query").UseMutationResult<unknown, Error, TransferGroupOwnerParams, unknown>;
24
+ interface SetGroupMemberPermissionsParams {
25
+ groupID: string;
26
+ userID: string;
27
+ permissions: string[];
28
+ }
29
+ export declare const useSetGroupMemberPermissions: () => import("@tanstack/react-query").UseMutationResult<unknown, Error, SetGroupMemberPermissionsParams, unknown>;
24
30
  export {};
25
31
  //# sourceMappingURL=useGroupMemberActions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useGroupMemberActions.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useGroupMemberActions.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAQ/D,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAED,eAAO,MAAM,kBAAkB,yGAW9B,CAAC;AAEF,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,kBAAkB,yGAW9B,CAAC;AAEF,UAAU,wBAAwB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,eAAe,CAAC;CAC5B;AAED,eAAO,MAAM,qBAAqB,4GAWjC,CAAC;AAEF,UAAU,wBAAwB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,qBAAqB,4GAUjC,CAAC"}
1
+ {"version":3,"file":"useGroupMemberActions.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useGroupMemberActions.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAmB,MAAM,8BAA8B,CAAC;AAQhF,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AAED,eAAO,MAAM,kBAAkB,yGAW9B,CAAC;AAEF,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,kBAAkB,yGAW9B,CAAC;AAEF,UAAU,wBAAwB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,eAAe,CAAC;CAC5B;AAED,eAAO,MAAM,qBAAqB,4GAWjC,CAAC;AAEF,UAAU,wBAAwB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,qBAAqB,4GAUjC,CAAC;AAEF,UAAU,+BAA+B;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,eAAO,MAAM,4BAA4B,mHAexC,CAAC"}
@@ -52,3 +52,15 @@ export const useTransferGroupOwner = () => {
52
52
  },
53
53
  });
54
54
  };
55
+ export const useSetGroupMemberPermissions = () => {
56
+ return useMutation({
57
+ mutationFn: async ({ groupID, userID, permissions, }) => {
58
+ const { data } = await DChatSDK.setGroupMemberInfo({
59
+ groupID,
60
+ userID,
61
+ permissions: permissions,
62
+ });
63
+ return data;
64
+ },
65
+ });
66
+ };
@@ -1,3 +1,4 @@
1
+ import { GroupMemberRole } from "@droppii-org/wasm-client-sdk";
1
2
  export interface GroupPermissions {
2
3
  sendMessage: boolean;
3
4
  pinMessage: boolean;
@@ -11,5 +12,6 @@ export interface GroupPermissions {
11
12
  configGroupPermission: boolean;
12
13
  viewMemberInformation: boolean;
13
14
  }
14
- export declare const useGroupPermission: (groupID?: string) => GroupPermissions;
15
+ export declare const permissionListToGroupPermissions: (permissionList: string[] | undefined, roleLevel: GroupMemberRole) => GroupPermissions;
16
+ export declare const useGroupPermission: (_groupID?: string) => GroupPermissions;
15
17
  //# sourceMappingURL=useGroupPermission.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useGroupPermission.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useGroupPermission.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,sBAAsB,EAAE,OAAO,CAAC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAiDD,eAAO,MAAM,kBAAkB,GAAI,UAAU,MAAM,KAAG,gBA6CrD,CAAC"}
1
+ {"version":3,"file":"useGroupPermission.d.ts","sourceRoot":"","sources":["../../../src/hooks/group/useGroupPermission.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAI/D,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,sBAAsB,EAAE,OAAO,CAAC;IAChC,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,qBAAqB,EAAE,OAAO,CAAC;CAChC;AA+CD,eAAO,MAAM,gCAAgC,GAC3C,gBAAgB,MAAM,EAAE,GAAG,SAAS,EACpC,WAAW,eAAe,KACzB,gBAcF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,WAAW,MAAM,KAAG,gBAYtD,CAAC"}