@droppii-org/chat-sdk 0.6.51 → 0.6.53

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 (69) hide show
  1. package/dist/components/group/AdminPermissionModal.d.ts.map +1 -1
  2. package/dist/components/group/AdminPermissionModal.js +9 -38
  3. package/dist/components/group/MemberPermissionPanel.d.ts.map +1 -1
  4. package/dist/components/group/MemberPermissionPanel.js +45 -33
  5. package/dist/components/search-conversation/SearchAll.d.ts.map +1 -1
  6. package/dist/components/search-conversation/SearchAll.js +7 -9
  7. package/dist/components/search-conversation/SearchConversationAsGroups.d.ts.map +1 -1
  8. package/dist/components/search-conversation/SearchConversationAsGroups.js +3 -0
  9. package/dist/components/search-conversation/SearchConversationAsMessages.d.ts.map +1 -1
  10. package/dist/components/search-conversation/SearchConversationAsMessages.js +4 -1
  11. package/dist/components/search-conversation/SearchConversationAsUsers.d.ts.map +1 -1
  12. package/dist/components/search-conversation/SearchConversationAsUsers.js +4 -6
  13. package/dist/components/search-conversation/SearchScopeContext.d.ts +4 -0
  14. package/dist/components/search-conversation/SearchScopeContext.d.ts.map +1 -0
  15. package/dist/components/search-conversation/SearchScopeContext.js +5 -0
  16. package/dist/components/search-conversation/index.d.ts +5 -2
  17. package/dist/components/search-conversation/index.d.ts.map +1 -1
  18. package/dist/components/search-conversation/index.js +17 -12
  19. package/dist/components/search-conversation/item/SearchItemAsGroup.d.ts.map +1 -1
  20. package/dist/components/search-conversation/item/SearchItemAsGroup.js +9 -0
  21. package/dist/components/search-conversation/item/SearchItemAsMessage.d.ts +2 -0
  22. package/dist/components/search-conversation/item/SearchItemAsMessage.d.ts.map +1 -1
  23. package/dist/components/search-conversation/item/SearchItemAsMessage.js +28 -6
  24. package/dist/components/search-conversation/item/SearchItemAsUser.d.ts +2 -1
  25. package/dist/components/search-conversation/item/SearchItemAsUser.d.ts.map +1 -1
  26. package/dist/components/search-conversation/item/SearchItemAsUser.js +9 -2
  27. package/dist/hooks/group/useGroupMemberActions.d.ts +7 -0
  28. package/dist/hooks/group/useGroupMemberActions.d.ts.map +1 -1
  29. package/dist/hooks/group/useGroupMemberActions.js +23 -0
  30. package/dist/hooks/message/useTypingStatus.d.ts.map +1 -1
  31. package/dist/hooks/message/useTypingStatus.js +1 -9
  32. package/dist/hooks/search/useOpenPdpSearchResult.d.ts +8 -0
  33. package/dist/hooks/search/useOpenPdpSearchResult.d.ts.map +1 -0
  34. package/dist/hooks/search/useOpenPdpSearchResult.js +31 -0
  35. package/dist/hooks/search/useSearchGroups.d.ts +3 -1
  36. package/dist/hooks/search/useSearchGroups.d.ts.map +1 -1
  37. package/dist/hooks/search/useSearchGroups.js +22 -11
  38. package/dist/hooks/search/useSearchMessage.d.ts +2 -0
  39. package/dist/hooks/search/useSearchMessage.d.ts.map +1 -1
  40. package/dist/hooks/search/useSearchMessage.js +10 -4
  41. package/dist/hooks/search/useSearchPdpTeamSessions.d.ts +17 -0
  42. package/dist/hooks/search/useSearchPdpTeamSessions.d.ts.map +1 -0
  43. package/dist/hooks/search/useSearchPdpTeamSessions.js +38 -0
  44. package/dist/hooks/search/useSearchUsers.d.ts +14 -0
  45. package/dist/hooks/search/useSearchUsers.d.ts.map +1 -0
  46. package/dist/hooks/search/useSearchUsers.js +23 -0
  47. package/dist/index.d.ts +3 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +3 -0
  50. package/dist/locales/vi/common.json +2 -0
  51. package/dist/services/query.d.ts +1 -0
  52. package/dist/services/query.d.ts.map +1 -1
  53. package/dist/services/query.js +1 -0
  54. package/dist/services/routes.d.ts +3 -0
  55. package/dist/services/routes.d.ts.map +1 -1
  56. package/dist/services/routes.js +3 -0
  57. package/dist/types/search.d.ts +2 -0
  58. package/dist/types/search.d.ts.map +1 -0
  59. package/dist/types/search.js +1 -0
  60. package/dist/utils/conversation.d.ts +2 -1
  61. package/dist/utils/conversation.d.ts.map +1 -1
  62. package/dist/utils/conversation.js +8 -1
  63. package/dist/utils/groupPermissionSwitches.d.ts +9 -0
  64. package/dist/utils/groupPermissionSwitches.d.ts.map +1 -0
  65. package/dist/utils/groupPermissionSwitches.js +19 -0
  66. package/package.json +2 -2
  67. package/dist/store/groupPermissionOverrides.d.ts +0 -23
  68. package/dist/store/groupPermissionOverrides.d.ts.map +0 -1
  69. package/dist/store/groupPermissionOverrides.js +0 -12
@@ -1 +1 @@
1
- {"version":3,"file":"AdminPermissionModal.d.ts","sourceRoot":"","sources":["../../../src/components/group/AdminPermissionModal.tsx"],"names":[],"mappings":"AAaA,UAAU,0BAA0B;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,UAAU,yBAAyB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IAIpB,MAAM,CAAC,EAAE,OAAO,CAAC;IAGjB,MAAM,CAAC,EAAE,0BAA0B,CAAC;IAKpC,wBAAwB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAC5E;AA6DD,QAAA,MAAM,oBAAoB,GAAI,uEAO3B,yBAAyB,mDA2K3B,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"AdminPermissionModal.d.ts","sourceRoot":"","sources":["../../../src/components/group/AdminPermissionModal.tsx"],"names":[],"mappings":"AAqBA,UAAU,0BAA0B;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,UAAU,yBAAyB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IAIpB,MAAM,CAAC,EAAE,OAAO,CAAC;IAGjB,MAAM,CAAC,EAAE,0BAA0B,CAAC;IAKpC,wBAAwB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAC5E;AAwCD,QAAA,MAAM,oBAAoB,GAAI,uEAO3B,yBAAyB,mDAgK3B,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -5,10 +5,11 @@ import { ConfigProvider, Modal, Switch, message } from "antd";
5
5
  import { useTranslation } from "react-i18next";
6
6
  import { GroupMemberRole } from "@droppii-org/wasm-client-sdk";
7
7
  import { useGroupMembers } from "../../hooks/group/useGroupMembers";
8
- import { useSetGroupMemberPermissions } from "../../hooks/group/useGroupMemberActions";
8
+ import { useSetAdminRolePermissions, useSetGroupMemberPermissions, } from "../../hooks/group/useGroupMemberActions";
9
9
  import { Icon } from "../../components/icon";
10
10
  import { ANTD_PRIMARY_COLOR_VAR } from "../../constants";
11
11
  import { GROUP_PERMISSION_KEY } from "../../constants/im";
12
+ import { changedSwitches, commonSwitchStates, toRolePermissionChange, } from "../../utils/groupPermissionSwitches";
12
13
  // "Cập nhật thông tin nhóm" is one switch in the UI but bundles 3 BE
13
14
  // permission keys (name/avatar/description), so it maps to all three.
14
15
  const UPDATE_GROUP_INFO_KEYS = [
@@ -24,35 +25,21 @@ const SWITCH_PERMISSION_KEYS = {
24
25
  removeMember: [GROUP_PERMISSION_KEY.removeMember],
25
26
  updateGroupInfo: UPDATE_GROUP_INFO_KEYS,
26
27
  };
27
- const SWITCHES = Object.keys(SWITCH_PERMISSION_KEYS);
28
- // A switch reads on only when every given permission list grants all of its keys.
29
- const commonOverrides = (permissionLists) => {
30
- const grants = (name) => permissionLists.length > 0 &&
31
- permissionLists.every((list) => SWITCH_PERMISSION_KEYS[name].every((key) => list.includes(key)));
32
- return {
33
- sendMessage: grants("sendMessage"),
34
- pinMessage: grants("pinMessage"),
35
- viewMemberInformation: grants("viewMemberInformation"),
36
- addMember: grants("addMember"),
37
- removeMember: grants("removeMember"),
38
- updateGroupInfo: grants("updateGroupInfo"),
39
- };
40
- };
41
28
  // Rewrites only the switches that changed; every other key in the list stays as is.
42
29
  const applySwitchChanges = (permissionList, changes) => Object.entries(changes).reduce((list, [name, enabled]) => {
43
30
  const keys = SWITCH_PERMISSION_KEYS[name];
44
31
  const without = list.filter((permission) => !keys.includes(permission));
45
32
  return enabled ? [...without, ...keys] : without;
46
33
  }, permissionList);
47
- const isSamePermissionSet = (a, b) => a.length === b.length && a.every((permission) => b.includes(permission));
48
34
  // "Configure Admin Permissions". With `member` (a member row's … menu) it edits
49
35
  // that one Admin. Without it (the group info panel) it edits every current
50
- // Admin at once: switches start from what the Admins already share, and "Lưu"
51
- // writes only the switches the user flipped, so each Admin keeps the rest.
36
+ // Admin in one setGroupAdminPermissions call: switches start from what the
37
+ // Admins already share, and "Lưu" sends only the switches the user flipped.
52
38
  const AdminPermissionModal = ({ open, groupID, onClose, inline = false, member, onMemberPermissionsSaved, }) => {
53
39
  const { t } = useTranslation();
54
40
  const { members: groupMembers } = useGroupMembers(member ? undefined : groupID);
55
41
  const { mutateAsync: setMemberPermissions } = useSetGroupMemberPermissions();
42
+ const { mutateAsync: setAdminRolePermissions } = useSetAdminRolePermissions();
56
43
  const [isSaving, setIsSaving] = useState(false);
57
44
  const [edits, setEdits] = useState({});
58
45
  useEffect(() => {
@@ -60,19 +47,14 @@ const AdminPermissionModal = ({ open, groupID, onClose, inline = false, member,
60
47
  setEdits({});
61
48
  }, [open, member === null || member === void 0 ? void 0 : member.userID]);
62
49
  const admins = groupMembers.filter((groupMember) => groupMember.roleLevel === GroupMemberRole.Admin);
63
- const baseline = member
64
- ? commonOverrides([member.permissions])
65
- : commonOverrides(admins.map((admin) => { var _a; return (_a = admin.permissions) !== null && _a !== void 0 ? _a : []; }));
50
+ const baseline = commonSwitchStates(SWITCH_PERMISSION_KEYS, member ? [member.permissions] : admins.map((admin) => { var _a; return (_a = admin.permissions) !== null && _a !== void 0 ? _a : []; }));
66
51
  const pending = Object.assign(Object.assign({}, baseline), edits);
67
- const changes = Object.fromEntries(SWITCHES.filter((name) => pending[name] !== baseline[name]).map((name) => [
68
- name,
69
- pending[name],
70
- ]));
52
+ const changes = changedSwitches(baseline, pending);
71
53
  const hasChanges = Object.keys(changes).length > 0;
72
54
  const setSwitch = (name, checked) => setEdits((prev) => (Object.assign(Object.assign({}, prev), { [name]: checked })));
73
55
  const handleSave = async () => {
74
56
  var _a, _b;
75
- if (!groupID)
57
+ if (!groupID || !hasChanges)
76
58
  return;
77
59
  setIsSaving(true);
78
60
  try {
@@ -86,18 +68,7 @@ const AdminPermissionModal = ({ open, groupID, onClose, inline = false, member,
86
68
  onMemberPermissionsSaved === null || onMemberPermissionsSaved === void 0 ? void 0 : onMemberPermissionsSaved(member.userID, nextPermissions);
87
69
  }
88
70
  else {
89
- await Promise.all(admins.map((admin) => {
90
- var _a;
91
- const current = (_a = admin.permissions) !== null && _a !== void 0 ? _a : [];
92
- const nextPermissions = applySwitchChanges(current, changes);
93
- if (isSamePermissionSet(current, nextPermissions))
94
- return undefined;
95
- return setMemberPermissions({
96
- groupID,
97
- userID: admin.userID,
98
- permissions: nextPermissions,
99
- });
100
- }));
71
+ await setAdminRolePermissions(Object.assign({ groupID }, toRolePermissionChange(SWITCH_PERMISSION_KEYS, changes)));
101
72
  }
102
73
  message.success(t("update_admin_permissions_success"));
103
74
  onClose();
@@ -1 +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"}
1
+ {"version":3,"file":"MemberPermissionPanel.d.ts","sourceRoot":"","sources":["../../../src/components/group/MemberPermissionPanel.tsx"],"names":[],"mappings":"AAkBA,UAAU,0BAA0B;IAClC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAuBD,QAAA,MAAM,qBAAqB,GAAI,4BAA4B,0BAA0B,mDA2FpF,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -3,51 +3,63 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useState } from "react";
4
4
  import { ConfigProvider, Switch, message } from "antd";
5
5
  import { useTranslation } from "react-i18next";
6
- import { useGroupPermission } from "../../hooks/group/useGroupPermission";
6
+ import { GroupMemberRole } from "@droppii-org/wasm-client-sdk";
7
+ import { useGroupMembers } from "../../hooks/group/useGroupMembers";
8
+ import { useSetMemberRolePermissions } from "../../hooks/group/useGroupMemberActions";
7
9
  import { Icon } from "../../components/icon";
8
10
  import { ANTD_PRIMARY_COLOR_VAR } 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.
11
+ import { GROUP_PERMISSION_KEY } from "../../constants/im";
12
+ import { changedSwitches, commonSwitchStates, toRolePermissionChange, } from "../../utils/groupPermissionSwitches";
13
+ const SWITCH_PERMISSION_KEYS = {
14
+ sendMessage: [GROUP_PERMISSION_KEY.sendMessage],
15
+ addMember: [GROUP_PERMISSION_KEY.addMember],
16
+ pinMessage: [GROUP_PERMISSION_KEY.pinMessage],
17
+ viewMemberInformation: [GROUP_PERMISSION_KEY.viewMemberInformation],
18
+ };
19
+ const SWITCH_LABELS = {
20
+ sendMessage: "permission_send_message",
21
+ addMember: "permission_add_member",
22
+ pinMessage: "permission_pin_message",
23
+ viewMemberInformation: "permission_view_member_info",
24
+ };
25
+ const SWITCHES = Object.keys(SWITCH_PERMISSION_KEYS);
26
+ // "Configure Member Permissions", inline in the "Thông tin" sidebar. Switches
27
+ // start from what every ordinary member already shares, and "Lưu" sends only
28
+ // the switches the user flipped, in one setGroupMemberPermissions call.
14
29
  const MemberPermissionPanel = ({ open, groupID, onClose }) => {
15
30
  const { t } = useTranslation();
16
- const permissions = useGroupPermission(groupID);
17
- const setMemberOverrides = useGroupPermissionOverridesStore((state) => state.setMemberOverrides);
31
+ const { members: groupMembers, isLoading } = useGroupMembers(open ? groupID : undefined);
32
+ const { mutateAsync: setMemberRolePermissions } = useSetMemberRolePermissions();
18
33
  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
- });
34
+ const [edits, setEdits] = useState({});
25
35
  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
36
+ if (open)
37
+ setEdits({});
35
38
  }, [open]);
36
- const hasChanges = pending.sendMessage !== permissions.sendMessage ||
37
- pending.addMember !== permissions.addMember ||
38
- pending.pinMessage !== permissions.pinMessage ||
39
- pending.viewMemberInformation !== permissions.viewMemberInformation;
39
+ const members = groupMembers.filter((groupMember) => groupMember.roleLevel === GroupMemberRole.Normal);
40
+ const baseline = commonSwitchStates(SWITCH_PERMISSION_KEYS, members.map((member) => { var _a; return (_a = member.permissions) !== null && _a !== void 0 ? _a : []; }));
41
+ const pending = Object.assign(Object.assign({}, baseline), edits);
42
+ const changes = changedSwitches(baseline, pending);
43
+ const hasChanges = Object.keys(changes).length > 0;
40
44
  const handleSave = async () => {
41
- if (!groupID)
45
+ if (!groupID || !hasChanges)
42
46
  return;
43
47
  setIsSaving(true);
44
- setMemberOverrides(groupID, pending);
45
- message.success(t("update_member_permissions_success"));
46
- setIsSaving(false);
47
- onClose();
48
+ try {
49
+ await setMemberRolePermissions(Object.assign({ groupID }, toRolePermissionChange(SWITCH_PERMISSION_KEYS, changes)));
50
+ message.success(t("update_member_permissions_success"));
51
+ onClose();
52
+ }
53
+ catch (error) {
54
+ console.error("setGroupMemberPermissions", error);
55
+ message.error(t("update_member_permissions_failed"));
56
+ }
57
+ finally {
58
+ setIsSaving(false);
59
+ }
48
60
  };
49
61
  if (!open)
50
62
  return null;
51
- return (_jsxs("div", { className: "absolute inset-0 bg-white flex flex-col z-10", "data-cp-name": "MemberPermissionPanel", 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-[var(--dc-color-nav-icon)]", 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: ANTD_PRIMARY_COLOR_VAR } }, 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-[var(--dc-color-primary)] text-white text-sm font-medium disabled:bg-gray-200 disabled:text-gray-400", disabled: !hasChanges || isSaving, onClick: handleSave, children: t("save") })] })] }));
63
+ return (_jsxs("div", { className: "absolute inset-0 bg-white flex flex-col z-10", "data-cp-name": "MemberPermissionPanel", 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-[var(--dc-color-nav-icon)]", 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: ANTD_PRIMARY_COLOR_VAR } }, children: _jsx("div", { className: "flex flex-col py-2", children: SWITCHES.map((name) => (_jsxs("div", { className: "flex items-center justify-between px-4 py-3", children: [_jsx("span", { className: "text-sm", children: t(SWITCH_LABELS[name]) }), _jsx(Switch, { checked: pending[name], disabled: isLoading, onChange: (checked) => setEdits((prev) => (Object.assign(Object.assign({}, prev), { [name]: checked }))) })] }, name))) }) }) }), _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-[var(--dc-color-primary)] text-white text-sm font-medium disabled:bg-gray-200 disabled:text-gray-400", disabled: !hasChanges || isSaving || isLoading, onClick: handleSave, children: t("save") })] })] }));
52
64
  };
53
65
  export default MemberPermissionPanel;
@@ -1 +1 @@
1
- {"version":3,"file":"SearchAll.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/SearchAll.tsx"],"names":[],"mappings":"AAWA,OAAO,EAAE,wBAAwB,EAAE,MAAM,GAAG,CAAC;AAG7C,UAAU,0BAA0B;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,CAAC,GAAG,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACvD;AACD,QAAA,MAAM,qBAAqB,GAAI,+BAG5B,0BAA0B,4CA2J5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"SearchAll.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/SearchAll.tsx"],"names":[],"mappings":"AAWA,OAAO,EAAE,wBAAwB,EAAE,MAAM,GAAG,CAAC;AAI7C,UAAU,0BAA0B;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,CAAC,GAAG,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACvD;AACD,QAAA,MAAM,qBAAqB,GAAI,+BAG5B,0BAA0B,4CAyJ5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -6,30 +6,28 @@ import { useSearchMessage } from "../../hooks/search/useSearchMessage";
6
6
  import { MessageType } from "@droppii-org/wasm-client-sdk";
7
7
  import { Icon } from "../../components/icon";
8
8
  import SearchItemAsMessage from "./item/SearchItemAsMessage";
9
- import { useGetSession } from "../../hooks/session/useGetSession";
10
9
  import SearchItemAsUser from "./item/SearchItemAsUser";
11
10
  import SearchItemAsGroup from "./item/SearchItemAsGroup";
12
11
  import { useSearchGroups } from "../../hooks/search/useSearchGroups";
12
+ import { useSearchUsers } from "../../hooks/search/useSearchUsers";
13
13
  import { SearchConversationTabKey } from ".";
14
+ import { useSearchScope } from "./SearchScopeContext";
14
15
  import { PAGE_SIZE } from "../../constants";
15
16
  const SearchConversationAll = ({ searchTerm = "", setActiveKey, }) => {
16
17
  const { t } = useTranslation();
18
+ const scope = useSearchScope();
17
19
  const { dataFlatten: messages, isLoading: isLoadingMessage, hasNextPage: hasNextPageMessage, } = useSearchMessage({
18
20
  payload: {
19
21
  searchTerm: searchTerm.trim(),
20
22
  contentType: MessageType.TextMessage,
21
23
  },
22
- options: { pageSize: PAGE_SIZE.xs },
23
- });
24
- const { dataFlatten: sessions, isLoading: isLoadingSession, hasNextPage: hasNextPageSession, } = useGetSession({
25
- filter: {
26
- searchTerm: searchTerm.trim(),
27
- },
28
- options: { pageSize: PAGE_SIZE.xs },
24
+ options: { pageSize: PAGE_SIZE.xs, scope },
29
25
  });
26
+ const { dataFlatten: sessions, isLoading: isLoadingSession, hasNextPage: hasNextPageSession, } = useSearchUsers({ searchTerm, scope, pageSize: PAGE_SIZE.xs });
30
27
  const { groups, isLoading: isLoadingGroup, hasNextPage: hasNextPageGroup, } = useSearchGroups({
31
28
  searchTerm: searchTerm.trim(),
32
29
  pageSize: PAGE_SIZE.xs,
30
+ scope,
33
31
  });
34
32
  if (searchTerm.trim() === "" ||
35
33
  (messages.length === 0 && sessions.length === 0 && groups.length === 0)) {
@@ -38,6 +36,6 @@ const SearchConversationAll = ({ searchTerm = "", setActiveKey, }) => {
38
36
  if (isLoadingMessage || isLoadingSession || isLoadingGroup) {
39
37
  return (_jsx("div", { className: "h-full overflow-auto flex items-center justify-center", children: _jsx(Spin, {}) }));
40
38
  }
41
- return (_jsxs("div", { className: "h-full overflow-auto", "data-cp-name": "SearchConversationAll", children: [sessions.length > 0 && (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between px-3 min-h-[32px]", children: [_jsx("span", { className: "text-xs font-medium uppercase flex-1 text-gray-600", children: t("users") }), _jsx(Button, { type: "link", icon: _jsx(Icon, { icon: "angle-right-o", size: 18, className: "!align-[-4px]" }), iconPosition: "end", className: clsx("p-0 gap-1", !hasNextPageSession && "invisible"), onClick: () => setActiveKey === null || setActiveKey === void 0 ? void 0 : setActiveKey(SearchConversationTabKey.Users), children: t("see_more") })] }), _jsx("div", { children: sessions.map((session) => (_jsx(SearchItemAsUser, { session: session, searchTerm: searchTerm }, session.conversationId))) })] })), messages.length > 0 && (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between px-3 min-h-[32px]", children: [_jsx("span", { className: "text-xs font-medium uppercase flex-1 text-gray-600", children: t("messages") }), _jsx(Button, { type: "link", icon: _jsx(Icon, { icon: "angle-right-o", size: 18, className: "!align-[-4px]" }), iconPosition: "end", className: clsx("p-0 gap-1", !hasNextPageMessage && "invisible"), onClick: () => setActiveKey === null || setActiveKey === void 0 ? void 0 : setActiveKey(SearchConversationTabKey.Messages), children: t("see_more") })] }), _jsx("div", { children: messages.map((message) => (_jsx(SearchItemAsMessage, { message: message.chatLog, searchTerm: searchTerm, displayTag: message.displayTag }, message.chatLog.clientMsgID))) })] })), groups.length > 0 && (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between px-3 min-h-[32px]", children: [_jsx("span", { className: "text-xs font-medium uppercase flex-1 text-gray-600", children: t("groups") }), _jsx(Button, { type: "link", icon: _jsx(Icon, { icon: "angle-right-o", size: 18, className: "!align-[-4px]" }), iconPosition: "end", className: clsx("p-0 gap-1", !hasNextPageGroup && "invisible"), onClick: () => setActiveKey === null || setActiveKey === void 0 ? void 0 : setActiveKey(SearchConversationTabKey.Groups), children: t("see_more") })] }), _jsx("div", { children: groups.map((group) => (_jsx(SearchItemAsGroup, { group: group, searchTerm: searchTerm }, group.conversationId))) })] }))] }));
39
+ return (_jsxs("div", { className: "h-full overflow-auto", "data-cp-name": "SearchConversationAll", children: [sessions.length > 0 && (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between px-3 min-h-[32px]", children: [_jsx("span", { className: "text-xs font-medium uppercase flex-1 text-gray-600", children: t("users") }), _jsx(Button, { type: "link", icon: _jsx(Icon, { icon: "angle-right-o", size: 18, className: "!align-[-4px]" }), iconPosition: "end", className: clsx("p-0 gap-1", !hasNextPageSession && "invisible"), onClick: () => setActiveKey === null || setActiveKey === void 0 ? void 0 : setActiveKey(SearchConversationTabKey.Users), children: t("see_more") })] }), _jsx("div", { children: sessions.map((session) => (_jsx(SearchItemAsUser, { session: session, searchTerm: searchTerm }, session.conversationId))) })] })), messages.length > 0 && (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between px-3 min-h-[32px]", children: [_jsx("span", { className: "text-xs font-medium uppercase flex-1 text-gray-600", children: t("messages") }), _jsx(Button, { type: "link", icon: _jsx(Icon, { icon: "angle-right-o", size: 18, className: "!align-[-4px]" }), iconPosition: "end", className: clsx("p-0 gap-1", !hasNextPageMessage && "invisible"), onClick: () => setActiveKey === null || setActiveKey === void 0 ? void 0 : setActiveKey(SearchConversationTabKey.Messages), children: t("see_more") })] }), _jsx("div", { children: messages.map((message) => (_jsx(SearchItemAsMessage, { message: message.chatLog, searchTerm: searchTerm, displayTag: message.displayTag, tag: message.tag }, message.chatLog.clientMsgID))) })] })), groups.length > 0 && (_jsxs("div", { children: [_jsxs("div", { className: "flex items-center justify-between px-3 min-h-[32px]", children: [_jsx("span", { className: "text-xs font-medium uppercase flex-1 text-gray-600", children: t("groups") }), _jsx(Button, { type: "link", icon: _jsx(Icon, { icon: "angle-right-o", size: 18, className: "!align-[-4px]" }), iconPosition: "end", className: clsx("p-0 gap-1", !hasNextPageGroup && "invisible"), onClick: () => setActiveKey === null || setActiveKey === void 0 ? void 0 : setActiveKey(SearchConversationTabKey.Groups), children: t("see_more") })] }), _jsx("div", { children: groups.map((group) => (_jsx(SearchItemAsGroup, { group: group, searchTerm: searchTerm }, group.conversationId))) })] }))] }));
42
40
  };
43
41
  export default SearchConversationAll;
@@ -1 +1 @@
1
- {"version":3,"file":"SearchConversationAsGroups.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/SearchConversationAsGroups.tsx"],"names":[],"mappings":"AAQA,UAAU,+BAA+B;IACvC,UAAU,EAAE,MAAM,CAAC;CACpB;AACD,QAAA,MAAM,0BAA0B,GAAI,OAAO,+BAA+B,4CA0CzE,CAAC;AAEF,eAAe,0BAA0B,CAAC"}
1
+ {"version":3,"file":"SearchConversationAsGroups.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/SearchConversationAsGroups.tsx"],"names":[],"mappings":"AASA,UAAU,+BAA+B;IACvC,UAAU,EAAE,MAAM,CAAC;CACpB;AACD,QAAA,MAAM,0BAA0B,GAAI,OAAO,+BAA+B,4CA4CzE,CAAC;AAEF,eAAe,0BAA0B,CAAC"}
@@ -5,11 +5,14 @@ import { useTranslation } from "react-i18next";
5
5
  import InfiniteScroll from "react-infinite-scroll-component";
6
6
  import SearchItemAsGroup from "./item/SearchItemAsGroup";
7
7
  import { useSearchGroups } from "../../hooks/search/useSearchGroups";
8
+ import { useSearchScope } from "./SearchScopeContext";
8
9
  const SearchConversationAsGroups = (props) => {
9
10
  const { searchTerm = "" } = props;
10
11
  const { t } = useTranslation();
12
+ const scope = useSearchScope();
11
13
  const { groups, hasNextPage, fetchNextPage, isLoading } = useSearchGroups({
12
14
  searchTerm,
15
+ scope,
13
16
  });
14
17
  if ((groups.length === 0 && !isLoading) || searchTerm.trim() === "")
15
18
  return _jsx(Empty, { description: t("no_conversation") });
@@ -1 +1 @@
1
- {"version":3,"file":"SearchConversationAsMessages.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/SearchConversationAsMessages.tsx"],"names":[],"mappings":"AAOA,UAAU,iCAAiC;IACzC,UAAU,EAAE,MAAM,CAAC;CACpB;AACD,QAAA,MAAM,4BAA4B,GAChC,OAAO,iCAAiC,4CAgDzC,CAAC;AAEF,eAAe,4BAA4B,CAAC"}
1
+ {"version":3,"file":"SearchConversationAsMessages.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/SearchConversationAsMessages.tsx"],"names":[],"mappings":"AAQA,UAAU,iCAAiC;IACzC,UAAU,EAAE,MAAM,CAAC;CACpB;AACD,QAAA,MAAM,4BAA4B,GAChC,OAAO,iCAAiC,4CAmDzC,CAAC;AAEF,eAAe,4BAA4B,CAAC"}
@@ -5,19 +5,22 @@ import { useSearchMessage } from "../../hooks/search/useSearchMessage";
5
5
  import { MessageType } from "@droppii-org/wasm-client-sdk";
6
6
  import InfiniteScroll from "react-infinite-scroll-component";
7
7
  import SearchItemAsMessage from "./item/SearchItemAsMessage";
8
+ import { useSearchScope } from "./SearchScopeContext";
8
9
  const SearchConversationAsMessages = (props) => {
9
10
  const { searchTerm = "" } = props;
10
11
  const { t } = useTranslation();
12
+ const scope = useSearchScope();
11
13
  const { dataFlatten, hasNextPage, fetchNextPage, isLoading } = useSearchMessage({
12
14
  payload: {
13
15
  searchTerm: searchTerm.trim(),
14
16
  contentType: MessageType.TextMessage,
15
17
  },
18
+ options: { scope },
16
19
  });
17
20
  if ((dataFlatten.length === 0 && !isLoading) || searchTerm.trim() === "")
18
21
  return _jsx(Empty, { description: t("no_conversation") });
19
22
  if (isLoading)
20
23
  return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
21
- return (_jsx("div", { id: "scrollableSearchMessagesTab", className: "h-full overflow-auto", "data-cp-name": "SearchConversationAsMessages", children: _jsx(InfiniteScroll, { dataLength: dataFlatten.length, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableSearchMessagesTab", children: dataFlatten.map((item) => (_jsx(SearchItemAsMessage, { message: item.chatLog, searchTerm: searchTerm, displayTag: item.displayTag }, item.chatLog.clientMsgID))) }) }));
24
+ return (_jsx("div", { id: "scrollableSearchMessagesTab", className: "h-full overflow-auto", "data-cp-name": "SearchConversationAsMessages", children: _jsx(InfiniteScroll, { dataLength: dataFlatten.length, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableSearchMessagesTab", children: dataFlatten.map((item) => (_jsx(SearchItemAsMessage, { message: item.chatLog, searchTerm: searchTerm, displayTag: item.displayTag, tag: item.tag }, item.chatLog.clientMsgID))) }) }));
22
25
  };
23
26
  export default SearchConversationAsMessages;
@@ -1 +1 @@
1
- {"version":3,"file":"SearchConversationAsUsers.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/SearchConversationAsUsers.tsx"],"names":[],"mappings":"AAMA,UAAU,8BAA8B;IACtC,UAAU,EAAE,MAAM,CAAC;CACpB;AACD,QAAA,MAAM,yBAAyB,GAAI,OAAO,8BAA8B,4CA4CvE,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
1
+ {"version":3,"file":"SearchConversationAsUsers.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/SearchConversationAsUsers.tsx"],"names":[],"mappings":"AAOA,UAAU,8BAA8B;IACtC,UAAU,EAAE,MAAM,CAAC;CACpB;AACD,QAAA,MAAM,yBAAyB,GAAI,OAAO,8BAA8B,4CA0CvE,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
@@ -3,15 +3,13 @@ import { Empty, Spin } from "antd";
3
3
  import { useTranslation } from "react-i18next";
4
4
  import InfiniteScroll from "react-infinite-scroll-component";
5
5
  import SearchItemAsUser from "./item/SearchItemAsUser";
6
- import { useGetSession } from "../../hooks/session/useGetSession";
6
+ import { useSearchUsers } from "../../hooks/search/useSearchUsers";
7
+ import { useSearchScope } from "./SearchScopeContext";
7
8
  const SearchConversationAsUsers = (props) => {
8
9
  const { searchTerm = "" } = props;
9
10
  const { t } = useTranslation();
10
- const { dataFlatten, hasNextPage, fetchNextPage, isLoading } = useGetSession({
11
- filter: {
12
- searchTerm: searchTerm.trim(),
13
- },
14
- });
11
+ const scope = useSearchScope();
12
+ const { dataFlatten, hasNextPage, fetchNextPage, isLoading } = useSearchUsers({ searchTerm, scope });
15
13
  if ((dataFlatten.length === 0 && !isLoading) || searchTerm.trim() === "")
16
14
  return _jsx(Empty, { description: t("no_conversation") });
17
15
  if (isLoading)
@@ -0,0 +1,4 @@
1
+ import type { SearchScope } from "../../types/search";
2
+ export declare const SearchScopeProvider: import("react").Provider<SearchScope>;
3
+ export declare const useSearchScope: () => SearchScope;
4
+ //# sourceMappingURL=SearchScopeContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchScopeContext.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/SearchScopeContext.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAIlD,eAAO,MAAM,mBAAmB,uCAA8B,CAAC;AAE/D,eAAO,MAAM,cAAc,mBAAuC,CAAC"}
@@ -0,0 +1,5 @@
1
+ "use client";
2
+ import { createContext, useContext } from "react";
3
+ const SearchScopeContext = createContext("crm");
4
+ export const SearchScopeProvider = SearchScopeContext.Provider;
5
+ export const useSearchScope = () => useContext(SearchScopeContext);
@@ -1,3 +1,4 @@
1
+ import type { SearchScope } from "../../types/search";
1
2
  export declare enum SearchConversationTabKey {
2
3
  All = "all",
3
4
  MyInbox = "myInbox",
@@ -5,9 +6,11 @@ export declare enum SearchConversationTabKey {
5
6
  Messages = "messages",
6
7
  Groups = "groups"
7
8
  }
8
- interface SearchConversationProps {
9
+ export interface SearchConversationProps {
9
10
  searchTerm: string;
11
+ /** Data sources + result navigation. Defaults to the CRM desk behavior. */
12
+ scope?: SearchScope;
10
13
  }
11
- declare const SearchConversation: ({ searchTerm }: SearchConversationProps) => import("react/jsx-runtime").JSX.Element;
14
+ declare const SearchConversation: ({ searchTerm, scope, }: SearchConversationProps) => import("react/jsx-runtime").JSX.Element;
12
15
  export default SearchConversation;
13
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/index.tsx"],"names":[],"mappings":"AAWA,oBAAY,wBAAwB;IAClC,GAAG,QAAQ;IACX,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,QAAQ,aAAa;IACrB,MAAM,WAAW;CAClB;AAED,UAAU,uBAAuB;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AACD,QAAA,MAAM,kBAAkB,GAAI,gBAAgB,uBAAuB,4CA4ElE,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/search-conversation/index.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD,oBAAY,wBAAwB;IAClC,GAAG,QAAQ;IACX,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,QAAQ,aAAa;IACrB,MAAM,WAAW;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AACD,QAAA,MAAM,kBAAkB,GAAI,wBAGzB,uBAAuB,4CAkFzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -8,6 +8,7 @@ import SearchConversationMyInbox from "./SearchConversationMyInbox";
8
8
  import SearchConversationAsUsers from "./SearchConversationAsUsers";
9
9
  import SearchConversationAsMessages from "./SearchConversationAsMessages";
10
10
  import SearchConversationAsGroups from "./SearchConversationAsGroups";
11
+ import { SearchScopeProvider } from "./SearchScopeContext";
11
12
  export var SearchConversationTabKey;
12
13
  (function (SearchConversationTabKey) {
13
14
  SearchConversationTabKey["All"] = "all";
@@ -16,11 +17,11 @@ export var SearchConversationTabKey;
16
17
  SearchConversationTabKey["Messages"] = "messages";
17
18
  SearchConversationTabKey["Groups"] = "groups";
18
19
  })(SearchConversationTabKey || (SearchConversationTabKey = {}));
19
- const SearchConversation = ({ searchTerm }) => {
20
+ const SearchConversation = ({ searchTerm, scope = "crm", }) => {
20
21
  const { t } = useTranslation();
21
22
  const [activeKey, setActiveKey] = useState(SearchConversationTabKey.All);
22
23
  const items = useMemo(() => {
23
- return [
24
+ const allItems = [
24
25
  {
25
26
  key: SearchConversationTabKey.All,
26
27
  label: t("all"),
@@ -47,7 +48,11 @@ const SearchConversation = ({ searchTerm }) => {
47
48
  children: _jsx(SearchConversationAsGroups, { searchTerm: searchTerm }),
48
49
  },
49
50
  ];
50
- }, [t, searchTerm]);
51
+ // PDP spec: the source inbox is never a search category.
52
+ return scope === "pdp-portal"
53
+ ? allItems.filter((item) => item.key !== SearchConversationTabKey.MyInbox)
54
+ : allItems;
55
+ }, [t, searchTerm, scope]);
51
56
  // Clicking a result row while on "All" switches activeKey without any
52
57
  // click/focus on the tab header itself — antd's own scroll-into-view for
53
58
  // that path relies on measuring .ant-tabs-nav against its scroll parent,
@@ -58,14 +63,14 @@ const SearchConversation = ({ searchTerm }) => {
58
63
  (_a = document
59
64
  .querySelector('[data-cp-name="SearchConversation"] .ant-tabs-tab-active')) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ inline: "nearest", block: "nearest" });
60
65
  }, [activeKey]);
61
- return (_jsx("div", { className: "h-full", "data-cp-name": "SearchConversation", children: _jsx(Tabs, { defaultActiveKey: SearchConversationTabKey.All, items: items, className: "h-full", activeKey: activeKey, onChange: (key) => setActiveKey(key), destroyOnHidden: true,
62
- // Ant's built-in tab-overflow ("...") dropdown never recovers from
63
- // its initial off-screen measurement inside this Drawer (rendered
64
- // with getContainer={false} for unrelated scroll-position reasons —
65
- // see DeskConversationList) — the last tab (Nhóm) becomes
66
- // permanently unreachable. A plain horizontally-scrollable strip
67
- // sidesteps that positioning bug entirely: every tab stays a real,
68
- // always-clickable element: no hidden dropdown involved.
69
- renderTabBar: (tabBarProps, DefaultTabBar) => (_jsx("div", { className: "overflow-x-auto", children: _jsx(DefaultTabBar, Object.assign({}, tabBarProps, { className: "!w-max" })) })) }) }));
66
+ return (_jsx(SearchScopeProvider, { value: scope, children: _jsx("div", { className: "h-full", "data-cp-name": "SearchConversation", children: _jsx(Tabs, { defaultActiveKey: SearchConversationTabKey.All, items: items, className: "h-full", activeKey: activeKey, onChange: (key) => setActiveKey(key), destroyOnHidden: true,
67
+ // Ant's built-in tab-overflow ("...") dropdown never recovers from
68
+ // its initial off-screen measurement inside this Drawer (rendered
69
+ // with getContainer={false} for unrelated scroll-position reasons —
70
+ // see DeskConversationList) — the last tab (Nhóm) becomes
71
+ // permanently unreachable. A plain horizontally-scrollable strip
72
+ // sidesteps that positioning bug entirely: every tab stays a real,
73
+ // always-clickable element: no hidden dropdown involved.
74
+ renderTabBar: (tabBarProps, DefaultTabBar) => (_jsx("div", { className: "overflow-x-auto", children: _jsx(DefaultTabBar, Object.assign({}, tabBarProps, { className: "!w-max" })) })) }) }) }));
70
75
  };
71
76
  export default SearchConversation;
@@ -1 +1 @@
1
- {"version":3,"file":"SearchItemAsGroup.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsGroup.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AAOxF,UAAU,sBAAsB;IAC9B,KAAK,EAAE,4BAA4B,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,iBAAiB,GAAI,OAAO,sBAAsB,4CAiEvD,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"SearchItemAsGroup.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsGroup.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AASxF,UAAU,sBAAsB;IAC9B,KAAK,EAAE,4BAA4B,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,iBAAiB,GAAI,OAAO,sBAAsB,4CAwEvD,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -7,15 +7,24 @@ import { useChatNavigate } from "../../../hooks/conversation/useChatNavigate";
7
7
  import { highlightSearch, sanitizeHtml } from "../../../utils/common";
8
8
  import { Icon } from "../../../components/icon";
9
9
  import GroupCompositeAvatar from "../../../components/group/GroupCompositeAvatar";
10
+ import { useOpenPdpSearchResult } from "../../../hooks/search/useOpenPdpSearchResult";
11
+ import { useSearchScope } from "../SearchScopeContext";
10
12
  const SearchItemAsGroup = (props) => {
11
13
  const { group, searchTerm = "" } = props;
12
14
  const { t } = useTranslation();
13
15
  const onNavigate = useChatNavigate();
16
+ const scope = useSearchScope();
17
+ const openPdpResult = useOpenPdpSearchResult();
14
18
  const setConversationData = useConversationStore((state) => state.setConversationData);
15
19
  const setSelectedConversationId = useConversationStore((state) => state.setSelectedConversationId);
16
20
  const { conversation } = group;
17
21
  const isPublic = group.visibility === GroupVisibility.Public;
18
22
  const onPressItem = () => {
23
+ // PDP's inbox opens real groups by ?groupId, same as its group list.
24
+ if (scope === "pdp-portal") {
25
+ openPdpResult({ groupId: group.groupId });
26
+ return;
27
+ }
19
28
  // Result can go stale before the click — force a fresh membership check.
20
29
  setConversationData(conversation, undefined, { forceRevalidate: true });
21
30
  setSelectedConversationId(conversation.conversationID);
@@ -5,6 +5,8 @@ interface SearchItemAsMessageProps {
5
5
  };
6
6
  searchTerm: string;
7
7
  displayTag?: string;
8
+ /** BE source tag (MY_INBOX | CS_TEAM); only PDP Portal renders from it. */
9
+ tag?: string;
8
10
  onClick?: () => void;
9
11
  }
10
12
  declare const SearchItemAsMessage: (props: SearchItemAsMessageProps) => import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"SearchItemAsMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsMessage.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAA4B,MAAM,8BAA8B,CAAC;AAerF,UAAU,wBAAwB;IAChC,OAAO,EAAE,WAAW,GAAG;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,mBAAmB,GAAI,OAAO,wBAAwB,4CA2G3D,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"SearchItemAsMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsMessage.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAA4B,MAAM,8BAA8B,CAAC;AAwBrF,UAAU,wBAAwB;IAChC,OAAO,EAAE,WAAW,GAAG;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,mBAAmB,GAAI,OAAO,wBAAwB,4CAyH3D,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -10,19 +10,41 @@ import { useTranslation } from "react-i18next";
10
10
  import useConversationStore from "../../../store/conversation";
11
11
  import { useMemo } from "react";
12
12
  import useAuthStore from "../../../store/auth";
13
+ import { getConversationIdFromMessage } from "../../../utils/conversation";
14
+ import { useOpenPdpSearchResult } from "../../../hooks/search/useOpenPdpSearchResult";
15
+ import { useSearchScope } from "../SearchScopeContext";
16
+ // PDP labels the source by its inbox tab; BE's displayTag carries the CS team name.
17
+ const PDP_TAG_LABEL_KEYS = {
18
+ MY_INBOX: "my_messages",
19
+ CS_TEAM: "pdp_team_inbox_tag",
20
+ };
13
21
  const SearchItemAsMessage = (props) => {
14
- var _a;
22
+ var _a, _b;
15
23
  const { t } = useTranslation();
16
- const { message, searchTerm = "", displayTag, onClick } = props;
24
+ const { message, searchTerm = "", displayTag, tag, onClick } = props;
17
25
  const { user } = useChatContext();
18
26
  const isCrm = useAuthStore((state) => state.isCrm);
27
+ const scope = useSearchScope();
28
+ const isPdpPortal = scope === "pdp-portal";
29
+ const openPdpResult = useOpenPdpSearchResult();
19
30
  const conversationData = useConversationStore((state) => state.conversationData);
20
31
  const useConversationDisplay = useMemo(() => {
21
- if (isCrm)
32
+ // PDP results span many threads, so show the sender like CRM does.
33
+ if (isCrm || isPdpPortal)
22
34
  return true;
23
35
  return (user === null || user === void 0 ? void 0 : user.userID) === (message === null || message === void 0 ? void 0 : message.sendID);
24
- }, [conversationData === null || conversationData === void 0 ? void 0 : conversationData.ex, message === null || message === void 0 ? void 0 : message.sendID, isCrm]);
36
+ }, [conversationData === null || conversationData === void 0 ? void 0 : conversationData.ex, message === null || message === void 0 ? void 0 : message.sendID, isCrm, isPdpPortal]);
37
+ const tagLabel = isPdpPortal
38
+ ? tag && PDP_TAG_LABEL_KEYS[tag] && t(PDP_TAG_LABEL_KEYS[tag])
39
+ : displayTag;
25
40
  const onPressItem = async () => {
41
+ if (isPdpPortal) {
42
+ openPdpResult({
43
+ threadId: getConversationIdFromMessage(message),
44
+ messageId: message.clientMsgID,
45
+ });
46
+ return;
47
+ }
26
48
  const { data } = await DChatSDK.getOneConversation({
27
49
  sourceID: message.sessionType === SessionType.Group
28
50
  ? message.groupID
@@ -63,13 +85,13 @@ const SearchItemAsMessage = (props) => {
63
85
  : conversationData === null || conversationData === void 0 ? void 0 : conversationData.faceURL, alt: useConversationDisplay
64
86
  ? message.senderNickname
65
87
  : conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName, children: useConversationDisplay
66
- ? message.senderNickname.charAt(0).toUpperCase()
88
+ ? (_b = message.senderNickname) === null || _b === void 0 ? void 0 : _b.charAt(0).toUpperCase()
67
89
  : conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName.charAt(0).toUpperCase() }) }), _jsxs("div", { className: "flex flex-col flex-1 min-w-0 gap-1", children: [_jsxs("div", { className: "flex flex-1 items-center justify-between", children: [_jsx("span", { className: "text-sm flex-1 font-semibold truncate", children: useConversationDisplay
68
90
  ? message.senderNickname
69
91
  : conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName }), _jsx("span", { className: "text-xs text-gray-500", children: formatTimestamp(message.sendTime, {
70
92
  hasTime: true,
71
93
  }) })] }), _jsxs("div", { className: "flex flex-col flex-1 min-w-0 gap-1", children: [_jsx("span", { className: "text-xs flex-1 text-gray-500 truncate", dangerouslySetInnerHTML: {
72
94
  __html: sanitizeHtml(highlightSearch(msgContent, searchTerm)),
73
- } }), displayTag && (_jsx("span", { className: "text-[10px] text-[var(--dc-color-primary)] bg-[var(--dc-color-primary-light)] px-1.5 py-0.5 rounded w-fit truncate", children: displayTag }))] })] })] }, message.clientMsgID));
95
+ } }), tagLabel && (_jsx("span", { className: "text-[10px] text-[var(--dc-color-primary)] bg-[var(--dc-color-primary-light)] px-1.5 py-0.5 rounded w-fit truncate", children: tagLabel }))] })] })] }, message.clientMsgID));
74
96
  };
75
97
  export default SearchItemAsMessage;
@@ -1,6 +1,7 @@
1
1
  import { ISessionByStatus } from "../../../store/type";
2
+ import type { PdpTeamSessionItem } from "../../../hooks/search/useSearchPdpTeamSessions";
2
3
  interface SearchItemAsUserProps {
3
- session: ISessionByStatus;
4
+ session: PdpTeamSessionItem & Partial<Pick<ISessionByStatus, "conversation">>;
4
5
  searchTerm: string;
5
6
  }
6
7
  declare const SearchItemAsUser: (props: SearchItemAsUserProps) => import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"SearchItemAsUser.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsUser.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAKhD,UAAU,qBAAqB;IAC7B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,gBAAgB,GAAI,OAAO,qBAAqB,4CA0CrD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"SearchItemAsUser.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsUser.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAIhD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAIlF,UAAU,qBAAqB;IAE7B,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC,CAAC;IAC9E,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,gBAAgB,GAAI,OAAO,qBAAqB,4CA+CrD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}