@droppii-org/chat-sdk 0.1.6 → 0.1.8

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 (108) hide show
  1. package/dist/assets/droppiiFontSelection.json +14521 -14521
  2. package/dist/assets/sdk/sql-wasm.wasm +0 -0
  3. package/dist/assets/svg/cannedResponse.tsx +48 -48
  4. package/dist/assets/svg/document.tsx +37 -37
  5. package/dist/assets/svg/index.ts +2 -2
  6. package/dist/components/cannedResponse/CannedResponseBody.d.ts.map +1 -1
  7. package/dist/components/cannedResponse/CannedResponseBody.js +54 -3
  8. package/dist/components/conversation/ConversationBySessionItem.d.ts.map +1 -1
  9. package/dist/components/conversation/ConversationBySessionItem.js +7 -2
  10. package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
  11. package/dist/components/conversation/DeskConversationList.js +22 -17
  12. package/dist/components/message/MessageHeader.d.ts +2 -2
  13. package/dist/components/message/MessageHeader.d.ts.map +1 -1
  14. package/dist/components/message/MessageHeader.js +5 -2
  15. package/dist/components/message/MessageList.d.ts.map +1 -1
  16. package/dist/components/message/MessageList.js +31 -22
  17. package/dist/components/message/SelectSession.d.ts.map +1 -1
  18. package/dist/components/message/SelectSession.js +7 -9
  19. package/dist/components/message/footer/ActionBar.d.ts.map +1 -1
  20. package/dist/components/message/footer/ActionBar.js +3 -2
  21. package/dist/components/message/footer/CannedResponsePlugin.d.ts.map +1 -1
  22. package/dist/components/message/footer/CannedResponsePlugin.js +37 -1
  23. package/dist/components/message/footer/ComposerEditor.d.ts +7 -0
  24. package/dist/components/message/footer/ComposerEditor.d.ts.map +1 -0
  25. package/dist/components/message/footer/ComposerEditor.js +13 -0
  26. package/dist/components/message/footer/ComposerTabs.d.ts +9 -0
  27. package/dist/components/message/footer/ComposerTabs.d.ts.map +1 -0
  28. package/dist/components/message/footer/ComposerTabs.js +37 -0
  29. package/dist/components/message/footer/EnterHandler.d.ts.map +1 -1
  30. package/dist/components/message/footer/EnterHandler.js +10 -1
  31. package/dist/components/message/footer/index.d.ts +2 -2
  32. package/dist/components/message/footer/index.d.ts.map +1 -1
  33. package/dist/components/message/footer/index.js +45 -9
  34. package/dist/components/message/item/index.d.ts.map +1 -1
  35. package/dist/components/message/item/index.js +11 -1
  36. package/dist/components/session/DeskAssignedSession.d.ts.map +1 -1
  37. package/dist/components/session/DeskAssignedSession.js +14 -109
  38. package/dist/components/session/DeskTeamInbox.d.ts +3 -0
  39. package/dist/components/session/DeskTeamInbox.d.ts.map +1 -0
  40. package/dist/components/session/DeskTeamInbox.js +56 -0
  41. package/dist/components/session/SessionFilterMenu.d.ts +13 -0
  42. package/dist/components/session/SessionFilterMenu.d.ts.map +1 -0
  43. package/dist/components/session/SessionFilterMenu.js +27 -0
  44. package/dist/components/session/sessionMenuItems.d.ts +26 -0
  45. package/dist/components/session/sessionMenuItems.d.ts.map +1 -0
  46. package/dist/components/session/sessionMenuItems.js +108 -0
  47. package/dist/hooks/conversation/useConversationPreview.d.ts +12 -0
  48. package/dist/hooks/conversation/useConversationPreview.d.ts.map +1 -0
  49. package/dist/hooks/conversation/useConversationPreview.js +22 -0
  50. package/dist/hooks/message/useConversationMessages.d.ts +27 -0
  51. package/dist/hooks/message/useConversationMessages.d.ts.map +1 -0
  52. package/dist/hooks/message/useConversationMessages.js +29 -0
  53. package/dist/hooks/message/useMessage.d.ts.map +1 -1
  54. package/dist/hooks/message/usePullSessionMessages.d.ts +9 -0
  55. package/dist/hooks/message/usePullSessionMessages.d.ts.map +1 -0
  56. package/dist/hooks/message/usePullSessionMessages.js +27 -0
  57. package/dist/hooks/message/useSendMessage.d.ts +8 -6
  58. package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
  59. package/dist/hooks/message/useSendMessage.js +8 -8
  60. package/dist/hooks/session/useConversationSessionState.d.ts +21 -0
  61. package/dist/hooks/session/useConversationSessionState.d.ts.map +1 -0
  62. package/dist/hooks/session/useConversationSessionState.js +41 -0
  63. package/dist/hooks/session/useGetSession.d.ts.map +1 -1
  64. package/dist/hooks/session/useGetSession.js +138 -52
  65. package/dist/hooks/session/useGetTeamSessionSummary.d.ts +3 -0
  66. package/dist/hooks/session/useGetTeamSessionSummary.d.ts.map +1 -0
  67. package/dist/hooks/session/useGetTeamSessionSummary.js +12 -0
  68. package/dist/hooks/session/useIsJoinedGroup.d.ts +5 -0
  69. package/dist/hooks/session/useIsJoinedGroup.d.ts.map +1 -0
  70. package/dist/hooks/session/useIsJoinedGroup.js +24 -0
  71. package/dist/hooks/session/useJoinGroupFlow.d.ts +12 -0
  72. package/dist/hooks/session/useJoinGroupFlow.d.ts.map +1 -0
  73. package/dist/hooks/session/useJoinGroupFlow.js +59 -0
  74. package/dist/hooks/session/useJoinSession.d.ts +3 -0
  75. package/dist/hooks/session/useJoinSession.d.ts.map +1 -0
  76. package/dist/hooks/session/useJoinSession.js +38 -0
  77. package/dist/hooks/user/useCurrentUserAccountType.d.ts +3 -0
  78. package/dist/hooks/user/useCurrentUserAccountType.d.ts.map +1 -0
  79. package/dist/hooks/user/useCurrentUserAccountType.js +30 -0
  80. package/dist/locales/i18n.ts +18 -18
  81. package/dist/locales/vi/common.json +112 -102
  82. package/dist/screens/chatBubble/index.d.ts +2 -2
  83. package/dist/screens/chatBubble/index.d.ts.map +1 -1
  84. package/dist/screens/chatBubble/index.js +13 -7
  85. package/dist/services/query.d.ts +5 -0
  86. package/dist/services/query.d.ts.map +1 -1
  87. package/dist/services/query.js +5 -0
  88. package/dist/services/routes.d.ts +5 -0
  89. package/dist/services/routes.d.ts.map +1 -1
  90. package/dist/services/routes.js +5 -0
  91. package/dist/store/conversation.d.ts.map +1 -1
  92. package/dist/store/conversation.js +41 -12
  93. package/dist/store/session.js +1 -1
  94. package/dist/styles/global.css +1 -1
  95. package/dist/tsconfig.tsbuildinfo +1 -1
  96. package/dist/types/chat.d.ts +18 -1
  97. package/dist/types/chat.d.ts.map +1 -1
  98. package/dist/types/chat.js +9 -0
  99. package/dist/types/dto.d.ts +87 -0
  100. package/dist/types/dto.d.ts.map +1 -1
  101. package/dist/utils/events.d.ts +1 -0
  102. package/dist/utils/events.d.ts.map +1 -1
  103. package/dist/utils/messageTransform.d.ts +5 -0
  104. package/dist/utils/messageTransform.d.ts.map +1 -0
  105. package/dist/utils/messageTransform.js +106 -0
  106. package/dist/utils/queryHelpers.d.ts.map +1 -1
  107. package/dist/utils/queryHelpers.js +2 -0
  108. package/package.json +11 -11
File without changes
@@ -1,48 +1,48 @@
1
- interface ISvgProps {
2
- size?: number;
3
- className?: string;
4
- }
5
-
6
- const CannedResponseIcon = (props: ISvgProps) => (
7
- <svg
8
- width={props.size || 18}
9
- height={props.size || 18}
10
- viewBox={`${0} ${0} ${props.size || 18} ${props.size || 18}`}
11
- fill="none"
12
- xmlns="http://www.w3.org/2000/svg"
13
- className={props?.className}
14
- >
15
- <g clipPath="url(#clip0_4070_70030)">
16
- <path
17
- fillRule="evenodd"
18
- clipRule="evenodd"
19
- d="M6.66732 0.833374C7.12755 0.833374 7.50065 1.20647 7.50065 1.66671L5.00065 18.3334C5.00065 18.7936 4.62755 19.1667 4.16732 19.1667C3.70708 19.1667 3.33398 18.7936 3.33398 18.3334L5.83398 1.66671C5.83398 1.20647 6.20708 0.833374 6.66732 0.833374Z"
20
- fill="currentColor"
21
- />
22
- <path
23
- fillRule="evenodd"
24
- clipRule="evenodd"
25
- d="M14.9993 0.833374C15.4596 0.833374 15.8327 1.20647 15.8327 1.66671L13.3327 18.3334C13.3327 18.7936 12.9596 19.1667 12.4993 19.1667C12.0391 19.1667 11.666 18.7936 11.666 18.3334L14.166 1.66671C14.166 1.20647 14.5391 0.833374 14.9993 0.833374Z"
26
- fill="currentColor"
27
- />
28
- <path
29
- fillRule="evenodd"
30
- clipRule="evenodd"
31
- d="M19.1673 5.83333C19.1673 6.29357 18.7942 6.66667 18.334 6.66667H1.66732C1.20708 6.66667 0.833984 6.29357 0.833984 5.83333C0.833984 5.37309 1.20708 5 1.66732 5H18.334C18.7942 5 19.1673 5.3731 19.1673 5.83333Z"
32
- fill="currentColor"
33
- />
34
- <path
35
- fillRule="evenodd"
36
- clipRule="evenodd"
37
- d="M19.1673 14.1667C19.1673 14.627 18.7942 15 18.334 15H1.66732C1.20708 15 0.833984 14.627 0.833984 14.1667C0.833984 13.7065 1.20708 13.3334 1.66732 13.3334H18.334C18.7942 13.3334 19.1673 13.7065 19.1673 14.1667Z"
38
- fill="currentColor"
39
- />
40
- </g>
41
- <defs>
42
- <clipPath id="clip0_4070_70030">
43
- <rect width={props.size || 18} height={props.size || 18} fill="white" />
44
- </clipPath>
45
- </defs>
46
- </svg>
47
- );
48
- export default CannedResponseIcon;
1
+ interface ISvgProps {
2
+ size?: number;
3
+ className?: string;
4
+ }
5
+
6
+ const CannedResponseIcon = (props: ISvgProps) => (
7
+ <svg
8
+ width={props.size || 18}
9
+ height={props.size || 18}
10
+ viewBox={`${0} ${0} ${props.size || 18} ${props.size || 18}`}
11
+ fill="none"
12
+ xmlns="http://www.w3.org/2000/svg"
13
+ className={props?.className}
14
+ >
15
+ <g clipPath="url(#clip0_4070_70030)">
16
+ <path
17
+ fillRule="evenodd"
18
+ clipRule="evenodd"
19
+ d="M6.66732 0.833374C7.12755 0.833374 7.50065 1.20647 7.50065 1.66671L5.00065 18.3334C5.00065 18.7936 4.62755 19.1667 4.16732 19.1667C3.70708 19.1667 3.33398 18.7936 3.33398 18.3334L5.83398 1.66671C5.83398 1.20647 6.20708 0.833374 6.66732 0.833374Z"
20
+ fill="currentColor"
21
+ />
22
+ <path
23
+ fillRule="evenodd"
24
+ clipRule="evenodd"
25
+ d="M14.9993 0.833374C15.4596 0.833374 15.8327 1.20647 15.8327 1.66671L13.3327 18.3334C13.3327 18.7936 12.9596 19.1667 12.4993 19.1667C12.0391 19.1667 11.666 18.7936 11.666 18.3334L14.166 1.66671C14.166 1.20647 14.5391 0.833374 14.9993 0.833374Z"
26
+ fill="currentColor"
27
+ />
28
+ <path
29
+ fillRule="evenodd"
30
+ clipRule="evenodd"
31
+ d="M19.1673 5.83333C19.1673 6.29357 18.7942 6.66667 18.334 6.66667H1.66732C1.20708 6.66667 0.833984 6.29357 0.833984 5.83333C0.833984 5.37309 1.20708 5 1.66732 5H18.334C18.7942 5 19.1673 5.3731 19.1673 5.83333Z"
32
+ fill="currentColor"
33
+ />
34
+ <path
35
+ fillRule="evenodd"
36
+ clipRule="evenodd"
37
+ d="M19.1673 14.1667C19.1673 14.627 18.7942 15 18.334 15H1.66732C1.20708 15 0.833984 14.627 0.833984 14.1667C0.833984 13.7065 1.20708 13.3334 1.66732 13.3334H18.334C18.7942 13.3334 19.1673 13.7065 19.1673 14.1667Z"
38
+ fill="currentColor"
39
+ />
40
+ </g>
41
+ <defs>
42
+ <clipPath id="clip0_4070_70030">
43
+ <rect width={props.size || 18} height={props.size || 18} fill="white" />
44
+ </clipPath>
45
+ </defs>
46
+ </svg>
47
+ );
48
+ export default CannedResponseIcon;
@@ -1,37 +1,37 @@
1
- export const documentIcon = (
2
- <svg
3
- width="40"
4
- height="40"
5
- viewBox="0 0 40 40"
6
- fill="none"
7
- xmlns="http://www.w3.org/2000/svg"
8
- >
9
- <path
10
- d="M10.1923 5.83301L23.4363 5.83301L34.1656 14.2054V29.8639C34.1656 31.8997 32.5286 34.1663 29.8068 34.1663C27.0849 34.1663 10.1923 34.1663 10.1923 34.1663C7.4704 34.1663 5.8335 31.8997 5.8335 29.8639V10.0305C5.8335 7.99475 7.4704 5.83301 10.1923 5.83301Z"
11
- fill="#24B0FF"
12
- ></path>
13
- <path
14
- d="M10.8335 28.1394V20.833H16.0309V22.4222H12.7026V23.5916H15.3612V25.1708H12.7026V28.1394H10.8335Z"
15
- fill="#edf6ff"
16
- ></path>
17
- <path
18
- d="M19.0073 28.0885V20.833H20.8613V26.5118H24.0146V28.0885L19.0073 28.0885Z"
19
- fill="#edf6ff"
20
- ></path>
21
- <path
22
- d="M16.5918 28.1001V20.833H18.4485V28.1001H16.5918Z"
23
- fill="#edf6ff"
24
- ></path>
25
- <path
26
- d="M24.5737 20.833V28.1393H29.7723V26.5573H26.439L26.4422 25.1708H29.1017V23.5916H26.4422V22.4222H29.7723V20.833H24.5737Z"
27
- fill="#edf6ff"
28
- ></path>
29
- <path
30
- opacity="0.302"
31
- fillRule="evenodd"
32
- clipRule="evenodd"
33
- d="M23.2686 5.83301V14.2281H34.1655L23.2686 5.83301Z"
34
- fill="#edf6ff"
35
- ></path>
36
- </svg>
37
- );
1
+ export const documentIcon = (
2
+ <svg
3
+ width="40"
4
+ height="40"
5
+ viewBox="0 0 40 40"
6
+ fill="none"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ >
9
+ <path
10
+ d="M10.1923 5.83301L23.4363 5.83301L34.1656 14.2054V29.8639C34.1656 31.8997 32.5286 34.1663 29.8068 34.1663C27.0849 34.1663 10.1923 34.1663 10.1923 34.1663C7.4704 34.1663 5.8335 31.8997 5.8335 29.8639V10.0305C5.8335 7.99475 7.4704 5.83301 10.1923 5.83301Z"
11
+ fill="#24B0FF"
12
+ ></path>
13
+ <path
14
+ d="M10.8335 28.1394V20.833H16.0309V22.4222H12.7026V23.5916H15.3612V25.1708H12.7026V28.1394H10.8335Z"
15
+ fill="#edf6ff"
16
+ ></path>
17
+ <path
18
+ d="M19.0073 28.0885V20.833H20.8613V26.5118H24.0146V28.0885L19.0073 28.0885Z"
19
+ fill="#edf6ff"
20
+ ></path>
21
+ <path
22
+ d="M16.5918 28.1001V20.833H18.4485V28.1001H16.5918Z"
23
+ fill="#edf6ff"
24
+ ></path>
25
+ <path
26
+ d="M24.5737 20.833V28.1393H29.7723V26.5573H26.439L26.4422 25.1708H29.1017V23.5916H26.4422V22.4222H29.7723V20.833H24.5737Z"
27
+ fill="#edf6ff"
28
+ ></path>
29
+ <path
30
+ opacity="0.302"
31
+ fillRule="evenodd"
32
+ clipRule="evenodd"
33
+ d="M23.2686 5.83301V14.2281H34.1655L23.2686 5.83301Z"
34
+ fill="#edf6ff"
35
+ ></path>
36
+ </svg>
37
+ );
@@ -1,2 +1,2 @@
1
- export * from "./document";
2
- export * from "./cannedResponse";
1
+ export * from "./document";
2
+ export * from "./cannedResponse";
@@ -1 +1 @@
1
- {"version":3,"file":"CannedResponseBody.d.ts","sourceRoot":"","sources":["../../../src/components/cannedResponse/CannedResponseBody.tsx"],"names":[],"mappings":"AAaA,UAAU,wBAAwB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,QAAA,MAAM,kBAAkB,GAAI,OAAO,wBAAwB,4CA6J1D,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"CannedResponseBody.d.ts","sourceRoot":"","sources":["../../../src/components/cannedResponse/CannedResponseBody.tsx"],"names":[],"mappings":"AAiBA,UAAU,wBAAwB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sBAAsB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AASD,QAAA,MAAM,kBAAkB,GAAI,OAAO,wBAAwB,4CA8M1D,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Empty, Segmented, Spin } from "antd";
3
3
  import { useFetchMyTeams } from "../../hooks/team/useFetchMyTeam";
4
4
  import { useTranslation } from "react-i18next";
5
- import { useCallback, useEffect, useMemo, useState } from "react";
5
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
6
6
  import { CannedResponseVisibleScope } from "../../types/chat";
7
7
  import TeamItem from "./team/TeamItem";
8
8
  import { useFetchCannedResponse } from "../../hooks/cannedResponse/useFetchCannedResponse";
@@ -10,9 +10,24 @@ import InfiniteScroll from "react-infinite-scroll-component";
10
10
  import { Icon } from "../icon";
11
11
  import { sanitizeHtml } from "../../utils/common";
12
12
  import { useDebounce } from "ahooks";
13
+ import clsx from "clsx";
14
+ import emitter from "../../utils/events";
15
+ import { isArray } from "lodash";
16
+ import { useMessageFooterContext } from "../message/footer";
17
+ const parseIndex = (index, length) => {
18
+ if (index === null)
19
+ return null;
20
+ if (index < 0)
21
+ return 0;
22
+ if (index >= length)
23
+ return length - 1;
24
+ return index;
25
+ };
13
26
  const CannedResponseBody = (props) => {
14
27
  var _a, _b;
15
28
  const { search, onSelectCannedResponse, cannedQuery } = props;
29
+ const { activeCannedIndex, setActiveCannedIndex, setMaxActiveCannedIndex } = useMessageFooterContext();
30
+ const itemRefs = useRef([]);
16
31
  const { t } = useTranslation();
17
32
  const { data: myTeams, isLoading: isLoadingTeams } = useFetchMyTeams();
18
33
  const [scope, setScope] = useState(CannedResponseVisibleScope.TEAM);
@@ -25,6 +40,9 @@ const CannedResponseBody = (props) => {
25
40
  categoryId: selectedCategoryId,
26
41
  shortcut: search || cannedQueryDebounced || "",
27
42
  });
43
+ const validActiveCannedIndex = useMemo(() => {
44
+ return parseIndex(activeCannedIndex, (cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length) || 0);
45
+ }, [activeCannedIndex, cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length]);
28
46
  const options = useMemo(() => {
29
47
  return [
30
48
  { label: t("team"), value: CannedResponseVisibleScope.TEAM },
@@ -43,12 +61,45 @@ const CannedResponseBody = (props) => {
43
61
  setSelectedTeamId(myTeams[0].teamId);
44
62
  }
45
63
  }, [isLoadingTeams, myTeams]);
46
- return (_jsxs("div", { className: "flex flex-1 flex-row h-[400px]", children: [_jsxs("div", { className: "w-[170px] p-2 border-r border-gray-200", children: [_jsx(Segmented, { options: options, block: true, size: "small", value: scope, onChange: setScope }), _jsx("div", { className: "overflow-y-auto h-full", children: scope === CannedResponseVisibleScope.TEAM && (_jsx("div", { className: "mt-1 flex flex-col", children: (_a = myTeams === null || myTeams === void 0 ? void 0 : myTeams.map) === null || _a === void 0 ? void 0 : _a.call(myTeams, (team, index) => renderTeamItem(team, index)) })) })] }), _jsxs("div", { id: "scrollableCannedDiv", className: "flex flex-col flex-1 h-full overflow-y-auto", children: [!!cannedQuery && !search && (_jsx("div", { className: "px-3 py-2 border-b border-gray-200", children: _jsxs("span", { className: "text-sm text-gray-500", children: [t("canned_response_quick_search_placeholder"), _jsx("span", { className: "text-blue-600", children: ` #${cannedQuery}` })] }) })), _jsx(InfiniteScroll, { dataLength: (cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length) || 0, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableCannedDiv", children: (cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length) === 0 ? (_jsx("div", { className: "flex items-center justify-center py-12", children: _jsx(Empty, { image: _jsx(Icon, { icon: "chat-square-b", size: 80, className: "text-gray-300" }), description: t("no_canned_response") }) })) : ((_b = cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.map) === null || _b === void 0 ? void 0 : _b.call(cannedResponses, (canned) => {
64
+ useEffect(() => {
65
+ const handler = (index) => {
66
+ var _a;
67
+ const validIndex = parseIndex(index, cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length);
68
+ if (validIndex !== null && !!(cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses[validIndex])) {
69
+ const htmlContent = ((_a = cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses[validIndex]) === null || _a === void 0 ? void 0 : _a.content) || "";
70
+ // 🔒 Sanitize HTML to prevent XSS attacks
71
+ const sanitizedContent = sanitizeHtml(htmlContent);
72
+ onSelectCannedResponse === null || onSelectCannedResponse === void 0 ? void 0 : onSelectCannedResponse(sanitizedContent);
73
+ }
74
+ };
75
+ emitter.on("CANNED_RESPONSE_SELECT", handler);
76
+ return () => {
77
+ emitter.off("CANNED_RESPONSE_SELECT", handler);
78
+ };
79
+ }, [cannedResponses, onSelectCannedResponse]);
80
+ useEffect(() => {
81
+ setActiveCannedIndex(0);
82
+ }, [search, cannedQueryDebounced, setActiveCannedIndex]);
83
+ useEffect(() => {
84
+ var _a, _b;
85
+ if (activeCannedIndex !== null) {
86
+ (_b = (_a = itemRefs.current) === null || _a === void 0 ? void 0 : _a[activeCannedIndex]) === null || _b === void 0 ? void 0 : _b.scrollIntoView({
87
+ block: "nearest",
88
+ });
89
+ }
90
+ }, [activeCannedIndex]);
91
+ useEffect(() => {
92
+ setMaxActiveCannedIndex((cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length) - 1 > 0 ? (cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length) - 1 : 0);
93
+ }, [cannedResponses, setMaxActiveCannedIndex]);
94
+ return (_jsxs("div", { className: "flex flex-1 flex-row h-[400px]", children: [_jsxs("div", { className: "w-[170px] p-2 border-r border-gray-200", children: [_jsx(Segmented, { options: options, block: true, size: "small", value: scope, onChange: setScope }), _jsx("div", { className: "overflow-y-auto h-full", children: scope === CannedResponseVisibleScope.TEAM && (_jsx("div", { className: "mt-1 flex flex-col", children: (_a = myTeams === null || myTeams === void 0 ? void 0 : myTeams.map) === null || _a === void 0 ? void 0 : _a.call(myTeams, (team, index) => renderTeamItem(team, index)) })) })] }), _jsxs("div", { id: "scrollableCannedDiv", className: "flex flex-col flex-1 h-full overflow-y-auto", children: [!!cannedQuery && !search && (_jsx("div", { className: "px-3 py-2 border-b border-gray-200", children: _jsxs("span", { className: "text-sm text-gray-500", children: [t("canned_response_quick_search_placeholder"), _jsx("span", { className: "text-blue-600", children: ` #${cannedQuery}` })] }) })), _jsx(InfiniteScroll, { dataLength: (cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length) || 0, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableCannedDiv", children: !isArray(cannedResponses) || (cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.length) === 0 ? (_jsx("div", { className: "flex items-center justify-center py-12", children: _jsx(Empty, { image: _jsx(Icon, { icon: "chat-square-b", size: 80, className: "text-gray-300" }), description: t("no_canned_response") }) })) : ((_b = cannedResponses === null || cannedResponses === void 0 ? void 0 : cannedResponses.map) === null || _b === void 0 ? void 0 : _b.call(cannedResponses, (canned, index) => {
47
95
  var _a, _b;
96
+ const isActive = index === validActiveCannedIndex;
48
97
  const htmlContent = (canned === null || canned === void 0 ? void 0 : canned.content) || "";
49
98
  // 🔒 Sanitize HTML to prevent XSS attacks
50
99
  const sanitizedContent = sanitizeHtml(htmlContent);
51
- return (_jsxs("div", { className: "flex flex-col flex-1 px-3 py-2 cursor-pointer hover:bg-blue-100 w-full border-b border-gray-200", onClick: () => onSelectCannedResponse === null || onSelectCannedResponse === void 0 ? void 0 : onSelectCannedResponse(sanitizedContent), children: [_jsxs("span", { className: "text-xs truncate text-gray-500", children: [`${((_a = canned === null || canned === void 0 ? void 0 : canned.category) === null || _a === void 0 ? void 0 : _a.name)
100
+ return (_jsxs("div", { ref: (el) => {
101
+ itemRefs.current[index] = el;
102
+ }, className: clsx("flex flex-col flex-1 px-3 py-2 cursor-pointer hover:bg-blue-100 w-full border-b border-gray-200", isActive && "bg-blue-100"), onClick: () => onSelectCannedResponse === null || onSelectCannedResponse === void 0 ? void 0 : onSelectCannedResponse(sanitizedContent), children: [_jsxs("span", { className: "text-xs truncate text-gray-500", children: [`${((_a = canned === null || canned === void 0 ? void 0 : canned.category) === null || _a === void 0 ? void 0 : _a.name)
52
103
  ? `${(_b = canned === null || canned === void 0 ? void 0 : canned.category) === null || _b === void 0 ? void 0 : _b.name} / `
53
104
  : ""}`, _jsx("span", { className: "text-black", children: `${(canned === null || canned === void 0 ? void 0 : canned.name) || ""} ` }), _jsx("span", { children: "/" }), _jsx("span", { className: "text-blue-500", children: ` #${(canned === null || canned === void 0 ? void 0 : canned.shortcut) || ""}` })] }), _jsx("div", { dangerouslySetInnerHTML: {
54
105
  __html: sanitizedContent,
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationBySessionItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ConversationBySessionItem.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAQpD,UAAU,8BAA8B;IACtC,WAAW,EAAE,gBAAgB,CAAC;CAC/B;AAED,QAAA,MAAM,yBAAyB,GAAI,kBAEhC,8BAA8B,mDA2FhC,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
1
+ {"version":3,"file":"ConversationBySessionItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ConversationBySessionItem.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AASpD,UAAU,8BAA8B;IACtC,WAAW,EAAE,gBAAgB,CAAC;CAC/B;AAED,QAAA,MAAM,yBAAyB,GAAI,kBAEhC,8BAA8B,mDAgGhC,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
@@ -6,6 +6,7 @@ import { usePathname, useRouter, useSearchParams } from "next/navigation";
6
6
  import { Avatar, Badge } from "antd";
7
7
  import { useChatContext } from "../../context/ChatContext";
8
8
  import { useConversationDisplayData } from "../../hooks/conversation/useConversation";
9
+ import { useConversationPreview } from "../../hooks/conversation/useConversationPreview";
9
10
  import { formatTimestamp, parseLatestMessage } from "../../utils/common";
10
11
  const ConversationBySessionItem = ({ sessionItem, }) => {
11
12
  var _a;
@@ -30,10 +31,14 @@ const ConversationBySessionItem = ({ sessionItem, }) => {
30
31
  setSelectedConversationId(conversation.conversationID);
31
32
  };
32
33
  const { avatar, displayName = "" } = useConversationDisplayData(conversation || null);
34
+ const { latestMsg, latestMsgSendTime } = useConversationPreview({
35
+ conversation,
36
+ ownerUserID: sessionItem.ownerId,
37
+ });
33
38
  if (!conversation)
34
39
  return null;
35
- return (_jsxs("div", { onClick: () => handleConversationClick(conversation), className: `relative p-3 border-b border-gray-100 hover:bg-gray-100 cursor-pointer transition-colors ${isSelected ? "bg-blue-50" : "bg-white"}`, children: [isSelected && (_jsx("div", { className: "absolute left-0 top-0 bottom-0 w-1 bg-blue-500" })), _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "relative flex-shrink-0", children: _jsx(Badge, { dot: true, status: "success", offset: [-2, 36], children: _jsx(Avatar, { size: 48, src: avatar, children: ((_a = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _a === void 0 ? void 0 : _a.call(displayName, 0)) || "A" }) }) }), _jsx("div", { className: "flex-1 min-w-0", children: _jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("h3", { className: "font-semibold text-gray-900 text-sm truncate", children: displayName }), _jsx("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: parseLatestMessage(conversation.latestMsg, user === null || user === void 0 ? void 0 : user.userID, t) })] }), _jsxs("div", { className: "flex flex-col items-end gap-1 ml-2", children: [_jsx("span", { className: "text-xs text-gray-400", children: formatTimestamp(conversation.latestMsgSendTime, {
40
+ return (_jsxs("div", { onClick: () => handleConversationClick(conversation), className: `relative p-3 border-b border-gray-100 hover:bg-gray-100 cursor-pointer transition-colors ${isSelected ? "bg-blue-50" : "bg-white"}`, children: [isSelected && (_jsx("div", { className: "absolute left-0 top-0 bottom-0 w-1 bg-blue-500" })), _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("div", { className: "relative flex-shrink-0", children: _jsx(Badge, { dot: true, status: "success", offset: [-2, 36], children: _jsx(Avatar, { size: 48, src: avatar, children: ((_a = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _a === void 0 ? void 0 : _a.call(displayName, 0)) || "A" }) }) }), _jsx("div", { className: "flex-1 min-w-0", children: _jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("h3", { className: "font-semibold text-gray-900 text-sm truncate", children: displayName }), _jsx("p", { className: "text-xs text-gray-500 truncate mt-0.5", children: parseLatestMessage(latestMsg, user === null || user === void 0 ? void 0 : user.userID, t) })] }), _jsxs("div", { className: "flex flex-col items-end gap-1 ml-2", children: [latestMsgSendTime > 0 && (_jsx("span", { className: "text-xs text-gray-400", children: formatTimestamp(latestMsgSendTime, {
36
41
  hasTime: true,
37
- }) }), _jsx("div", { className: "flex items-center gap-1", children: conversation.unreadCount > 0 && (_jsx(Badge, { count: conversation.unreadCount })) })] })] }) })] })] }, conversation.conversationID));
42
+ }) })), _jsx("div", { className: "flex items-center gap-1", children: conversation.unreadCount > 0 && (_jsx(Badge, { count: conversation.unreadCount })) })] })] }) })] })] }, conversation.conversationID));
38
43
  };
39
44
  export default ConversationBySessionItem;
@@ -1 +1 @@
1
- {"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AAkBA,QAAA,MAAM,oBAAoB,+CAwLzB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AAoBA,QAAA,MAAM,oBAAoB,+CAoMzB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -12,10 +12,12 @@ import useSessionStore from "../../store/session";
12
12
  import InfiniteScroll from "react-infinite-scroll-component";
13
13
  import ConversationBySessionItem from "./ConversationBySessionItem";
14
14
  import { useGetSession } from "../../hooks/session/useGetSession";
15
+ import { useGetTeamSessionSummary } from "../../hooks/session/useGetTeamSessionSummary";
15
16
  import { DChatSDK } from "../../constants/sdk";
16
17
  import emitter from "../../utils/events";
18
+ import { getFilterConfig } from "../session/sessionMenuItems";
17
19
  const DeskConversationList = () => {
18
- var _a;
20
+ var _a, _b;
19
21
  const searchInputRef = useRef(null);
20
22
  const { t } = useTranslation();
21
23
  const [search, setSearch] = useState("");
@@ -26,9 +28,13 @@ const DeskConversationList = () => {
26
28
  const conversationList = useConversationStore((state) => state.conversationList);
27
29
  const updateConversationList = useConversationStore((state) => state.updateConversationList);
28
30
  const filterSummary = useSessionStore((state) => state.filterSummary);
29
- const { dataFlatten: sessions, hasNextPage, fetchNextPage, refetch, } = useGetSession({
30
- filter: filterSummary,
31
- });
31
+ const { data: teamSummaries } = useGetTeamSessionSummary();
32
+ const { dataFlatten: sessions, hasNextPage, fetchNextPage, refetch } = useGetSession({ filter: filterSummary });
33
+ const currentFilterKey = filterSummary.status || filterSummary.tag || "";
34
+ const filterConfig = getFilterConfig(currentFilterKey);
35
+ const pathName = filterSummary.teamId
36
+ ? ((_a = teamSummaries === null || teamSummaries === void 0 ? void 0 : teamSummaries.find((team) => team.teamId === filterSummary.teamId)) === null || _a === void 0 ? void 0 : _a.teamName) || ""
37
+ : t("my_messages");
32
38
  const debouncedSearch = useDebounce(search, { wait: 500 });
33
39
  const onCloseSearch = () => {
34
40
  setSearch("");
@@ -65,28 +71,27 @@ const DeskConversationList = () => {
65
71
  }
66
72
  }, [searchParams, conversationList]);
67
73
  useEffect(() => {
68
- emitter.on("UPDATE_SESSION", (sessionUpdated) => {
74
+ const handler = (sessionUpdated) => {
69
75
  if (sessionUpdated.status !== filterSummary.status ||
70
76
  sessionUpdated.tag !== filterSummary.tag) {
71
77
  refetch();
72
78
  }
73
- });
79
+ };
80
+ emitter.on("UPDATE_SESSION", handler);
74
81
  return () => {
75
- emitter.off("UPDATE_SESSION", () => {
76
- refetch();
77
- });
82
+ emitter.off("UPDATE_SESSION", handler);
78
83
  };
79
- }, [filterSummary]);
80
- return (_jsxs("div", { className: `flex flex-col h-full bg-white border-r border-gray-200 w-[320px]`, children: [_jsx("div", { className: "p-3 border-b border-gray-100", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { ref: searchInputRef, placeholder: t("search"), prefix: _jsx(Icon, { icon: "search-o", size: 18, className: "text-gray-400" }), onChange: (e) => {
81
- if (!showSearch && e.target.value) {
82
- setShowSearchTrue();
83
- }
84
- setSearch(e.target.value);
85
- }, className: "rounded-lg text-sm flex-1 h-[36px]", size: "large", allowClear: true, onClick: setShowSearchTrue, value: search, autoFocus: false, onClear: onCloseSearch }), showSearch && (_jsx(Button, { onClick: onCloseSearch, variant: "outlined", className: "p-0 w-[36px] h-[36px] text-gray-500", children: _jsx(Icon, { icon: "close-b", size: 22 }) }))] }) }), _jsxs("div", { id: "scrollableConversationsDiv", style: {
84
+ }, [filterSummary, refetch]);
85
+ return (_jsxs("div", { className: "flex flex-col h-full bg-white border-r border-gray-200 w-[320px]", children: [_jsxs("div", { className: "p-3 border-b border-gray-100", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { ref: searchInputRef, placeholder: t("search"), prefix: _jsx(Icon, { icon: "search-o", size: 18, className: "text-gray-400" }), onChange: (e) => {
86
+ if (!showSearch && e.target.value) {
87
+ setShowSearchTrue();
88
+ }
89
+ setSearch(e.target.value);
90
+ }, className: "rounded-lg text-sm flex-1 h-[36px]", size: "large", allowClear: true, onClick: setShowSearchTrue, value: search, autoFocus: false, onClear: onCloseSearch }), showSearch && (_jsx(Button, { onClick: onCloseSearch, variant: "outlined", className: "p-0 w-[36px] h-[36px] text-gray-500", children: _jsx(Icon, { icon: "close-b", size: 22 }) }))] }), _jsxs("div", { className: "flex items-center justify-between mt-2", children: [_jsx("span", { className: "text-sm font-semibold text-blue-500 truncate", children: pathName }), filterConfig && (_jsxs("span", { className: "flex items-center gap-1.5 shrink-0", children: [_jsx(Icon, { icon: filterConfig.iconName, size: 16, className: "text-gray-500" }), _jsx("span", { className: "text-sm font-semibold text-gray-800", children: t(filterConfig.labelKey) })] }))] })] }), _jsxs("div", { id: "scrollableConversationsDiv", style: {
86
91
  height: "100%",
87
92
  overflow: showSearch ? "hidden" : "auto",
88
93
  position: "relative",
89
- }, children: [_jsx(InfiniteScroll, { dataLength: (sessions === null || sessions === void 0 ? void 0 : sessions.length) || 0, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableConversationsDiv", children: (sessions === null || sessions === void 0 ? void 0 : sessions.length) === 0 ? (_jsx("div", { className: "flex items-center justify-center py-12", children: _jsx(Empty, { image: _jsx(Icon, { icon: "chat-square-b", size: 80, className: "text-gray-300" }), description: t("no_conversation") }) })) : ((_a = sessions === null || sessions === void 0 ? void 0 : sessions.map) === null || _a === void 0 ? void 0 : _a.call(sessions, (session) => (_jsx(ConversationBySessionItem, { sessionItem: session }, session.conversationId)))) }), _jsx(Drawer, { open: showSearch, mask: false, closeIcon: false, styles: {
94
+ }, children: [_jsx(InfiniteScroll, { dataLength: (sessions === null || sessions === void 0 ? void 0 : sessions.length) || 0, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableConversationsDiv", children: (sessions === null || sessions === void 0 ? void 0 : sessions.length) === 0 ? (_jsx("div", { className: "flex items-center justify-center py-12", children: _jsx(Empty, { image: _jsx(Icon, { icon: "chat-square-b", size: 80, className: "text-gray-300" }), description: t("no_conversation") }) })) : ((_b = sessions === null || sessions === void 0 ? void 0 : sessions.map) === null || _b === void 0 ? void 0 : _b.call(sessions, (session) => (_jsx(ConversationBySessionItem, { sessionItem: session }, session.conversationId)))) }), _jsx(Drawer, { open: showSearch, mask: false, closeIcon: false, styles: {
90
95
  body: {
91
96
  padding: 0,
92
97
  },
@@ -1,8 +1,8 @@
1
1
  import { SessionStatus, SessionTag } from "../../types/chat";
2
- import { ISessionByStatus } from "../../store/type";
2
+ import { ISessionResponse } from "../../types/dto";
3
3
  interface MessageHeaderProps {
4
4
  onClose?: () => void;
5
- currentSession?: ISessionByStatus;
5
+ currentSession?: ISessionResponse;
6
6
  }
7
7
  type SelectSessionValueType = SessionStatus | SessionTag;
8
8
  export interface SelectSessionOption {
@@ -1 +1 @@
1
- {"version":3,"file":"MessageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageHeader.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAIpD,UAAU,kBAAkB;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,gBAAgB,CAAC;CACnC;AAED,KAAK,sBAAsB,GAAG,aAAa,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,sBAAsB,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,QAAA,MAAM,aAAa,GAAI,6BAA6B,kBAAkB,4CA4LrE,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"MessageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageHeader.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAKnD,UAAU,kBAAkB;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,gBAAgB,CAAC;CACnC;AAED,KAAK,sBAAsB,GAAG,aAAa,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,sBAAsB,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,QAAA,MAAM,aAAa,GAAI,6BAA6B,kBAAkB,4CAoMrE,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -12,13 +12,16 @@ import SelectSession from "./SelectSession";
12
12
  import { useUpdateSession } from "../../hooks/session/useUpdateSession";
13
13
  import useAuthStore from "../../store/auth";
14
14
  import SearchDrawer from "../searchConversation/SearchDrawer";
15
+ import { isGroupSession } from "../../utils/imCommon";
15
16
  const MessageHeader = ({ onClose, currentSession }) => {
16
- var _a;
17
+ var _a, _b;
17
18
  const { t } = useTranslation();
18
19
  const isCx = useAuthStore((state) => state.isCx);
19
20
  const conversationData = useConversationStore((state) => state.conversationData);
21
+ const currentGroupInfo = useConversationStore((state) => state.currentGroupInfo);
20
22
  const { mutate: updateSession } = useUpdateSession();
21
23
  const { avatar, displayName } = useConversationDisplayData(conversationData);
24
+ const shouldShowMemberCount = isGroupSession(conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationType);
22
25
  const [currentSessionStatus, setCurrentSessionStatus] = useState(SessionStatus.UNASSIGNED);
23
26
  const [currentSessionTag, setCurrentSessionTag] = useState(SessionTag.NONE);
24
27
  const statusOptions = useMemo(() => {
@@ -122,6 +125,6 @@ const MessageHeader = ({ onClose, currentSession }) => {
122
125
  setCurrentSessionStatus(currentSession.status);
123
126
  }
124
127
  }, [currentSession]);
125
- return (_jsxs("div", { className: "px-4 py-3 flex items-center border-b gap-3 bg-white flex-wrap", children: [_jsx(Avatar, { src: avatar, size: "large", className: "min-w-10 min-h-10", children: ((_a = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _a === void 0 ? void 0 : _a.call(displayName, 0)) || "A" }), _jsxs("div", { className: "flex flex-col overflow-hidden flex-1", children: [_jsx("p", { className: "text-base truncate", children: displayName || "" }), _jsx("p", { className: "text-xs text-gray-500 truncate", children: t("member_count", { count: 2 }) })] }), _jsxs("div", { className: "flex items-center gap-2 justify-end overflow-hidden", children: [isCx && (_jsx(SelectSession, { placeholder: t("select_tag"), options: tagOptions, value: currentSessionTag, onChange: (value) => handleUpdateSession(value, "tag", value === currentSessionTag), excludeOptions: [SessionTag.SLOW_PROCESSING, SessionTag.NONE] })), isCx && (_jsx(SelectSession, { placeholder: t("select_status"), options: statusOptions, value: currentSessionStatus, onChange: (value) => handleUpdateSession(value, "status", value === currentSessionStatus) })), _jsx(SearchDrawer, {}), _jsx(MediaCollection, {}), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", children: _jsx(Icon, { icon: "align-justify-o", size: 22 }) }), !!onClose && (_jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: onClose, children: _jsx(Icon, { icon: "close-b", size: 22 }) }))] })] }));
128
+ return (_jsxs("div", { className: "px-4 py-3 flex items-center border-b gap-3 bg-white flex-wrap", children: [_jsx(Avatar, { src: avatar, size: "large", className: "min-w-10 min-h-10", children: ((_a = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _a === void 0 ? void 0 : _a.call(displayName, 0)) || "A" }), _jsxs("div", { className: "flex flex-col overflow-hidden flex-1", children: [_jsx("p", { className: "text-base truncate", children: displayName || "" }), shouldShowMemberCount && (_jsx("p", { className: "text-xs text-gray-500 truncate", children: t("member_count", { count: (_b = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.memberCount) !== null && _b !== void 0 ? _b : 0 }) }))] }), _jsxs("div", { className: "flex items-center gap-2 justify-end overflow-hidden", children: [isCx && (_jsx(SelectSession, { placeholder: t("select_tag"), options: tagOptions, value: currentSessionTag, onChange: (value) => handleUpdateSession(value, "tag", value === currentSessionTag), excludeOptions: [SessionTag.SLOW_PROCESSING, SessionTag.NONE] })), isCx && (_jsx(SelectSession, { placeholder: t("select_status"), options: statusOptions, value: currentSessionStatus, onChange: (value) => handleUpdateSession(value, "status", value === currentSessionStatus) })), _jsx(SearchDrawer, {}), _jsx(MediaCollection, {}), _jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", children: _jsx(Icon, { icon: "align-justify-o", size: 22 }) }), !!onClose && (_jsx(Button, { type: "text", shape: "default", className: "text-gray-500 w-8 h-8 p-0", onClick: onClose, children: _jsx(Icon, { icon: "close-b", size: 22 }) }))] })] }));
126
129
  };
127
130
  export default MessageHeader;
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAyBA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AAGD,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAiT3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AA0BA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AAGD,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CA4U3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useMessage } from "../../hooks/message/useMessage";
4
- import { Empty, Modal, Spin } from "antd";
5
- import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+ import { useConversationMessages } from "../../hooks/message/useConversationMessages";
4
+ import { Button, Empty, Modal, Spin } from "antd";
5
+ import { useCallback, useEffect, useRef, useState } from "react";
6
6
  import dayjs from "dayjs";
7
7
  import isToday from "dayjs/plugin/isToday";
8
8
  import emitter from "../../utils/events";
@@ -18,8 +18,9 @@ import { useBoolean, useDebounceFn } from "ahooks";
18
18
  import { MSG_ITEM_CONTENT_PREFIX, MSG_ITEM_PREFIX } from "../../constants";
19
19
  import { markConversationMessageAsRead } from "../../hooks/conversation/useConversation";
20
20
  import { useChatContext } from "../../context/ChatContext";
21
- import { useGetSession } from "../../hooks/session/useGetSession";
22
21
  import { useRevokeMessage } from "../../hooks/message/useRevokeMessage";
22
+ import { useConversationSessionState } from "../../hooks/session/useConversationSessionState";
23
+ import { useJoinGroupFlow } from "../../hooks/session/useJoinGroupFlow";
23
24
  dayjs.extend(isToday);
24
25
  const BOTTOM_THRESHOLD = -5;
25
26
  const MessageList = (props) => {
@@ -28,19 +29,31 @@ const MessageList = (props) => {
28
29
  const { user } = useChatContext();
29
30
  const { onClose, conversationId, searchClientMsgID, openCreateCannedModal } = props;
30
31
  const scrollRef = useRef(null);
31
- const { getMoreOldMessages, moreOldLoading, loadState, getMoreNewMessages, moreNewLoading, latestLoadState, } = useMessage(conversationId, searchClientMsgID);
32
32
  const conversationData = useConversationStore((state) => state.conversationData);
33
33
  const setQuotedMessage = useConversationStore((state) => state.setQuotedMessage);
34
34
  const setSearchClientMsgID = useConversationStore((state) => state.setSearchClientMsgID);
35
- const { dataFlatten: sessions, refetch: refetchSession } = useGetSession({
36
- filter: {
37
- conversationIds: !!conversationId ? [conversationId] : [],
38
- },
39
- });
40
35
  const [openMenuId, setOpenMenuId] = useState(null);
41
36
  const [selectedItem, setSelectedItem] = useState(null);
42
37
  const [showConfirmRevoke, { setTrue: openConfirmRevoke, setFalse: closeConfirmRevoke },] = useBoolean(false);
43
38
  const { revokeMessage, loading: isRevoking } = useRevokeMessage();
39
+ const { isNotGroupMember, latestConversationSession, customerUserID, refetchConversationSessions, refetchIsJoined, } = useConversationSessionState({
40
+ conversationId,
41
+ conversationType: conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationType,
42
+ groupId: conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID,
43
+ userID: user === null || user === void 0 ? void 0 : user.userID,
44
+ });
45
+ const { getMoreOldMessages, moreOldLoading, loadState, getMoreNewMessages, moreNewLoading, latestLoadState, } = useConversationMessages({
46
+ conversationId,
47
+ searchClientMsgID,
48
+ restrictToLastSession: isNotGroupMember,
49
+ customerUserID,
50
+ });
51
+ const { handleJoinGroup, isJoining } = useJoinGroupFlow({
52
+ groupId: conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID,
53
+ latestConversationSessionId: latestConversationSession === null || latestConversationSession === void 0 ? void 0 : latestConversationSession.id,
54
+ refetchConversationSessions,
55
+ refetchIsJoined,
56
+ });
44
57
  const handleOpenRevoke = useCallback((clientMsgID) => {
45
58
  setSelectedItem(clientMsgID);
46
59
  openConfirmRevoke();
@@ -58,9 +71,6 @@ const MessageList = (props) => {
58
71
  revokeMessage,
59
72
  handleCloseRevoke,
60
73
  ]);
61
- const currentSession = useMemo(() => {
62
- return sessions === null || sessions === void 0 ? void 0 : sessions.find((session) => session.conversationId === conversationId);
63
- }, [sessions, conversationId]);
64
74
  const handleMarkConversationMessageAsRead = () => {
65
75
  var _a, _b, _c, _d, _e;
66
76
  const lastMessage = (_b = (_a = latestLoadState === null || latestLoadState === void 0 ? void 0 : latestLoadState.current) === null || _a === void 0 ? void 0 : _a.messageList) === null || _b === void 0 ? void 0 : _b[0];
@@ -136,17 +146,16 @@ const MessageList = (props) => {
136
146
  };
137
147
  }, []);
138
148
  useEffect(() => {
139
- emitter.on("UPDATE_SESSION", (sessionUpdated) => {
149
+ const handler = (sessionUpdated) => {
140
150
  if (sessionUpdated.conversationId === conversationId) {
141
- refetchSession();
151
+ refetchConversationSessions();
142
152
  }
143
- });
153
+ };
154
+ emitter.on("UPDATE_SESSION", handler);
144
155
  return () => {
145
- emitter.off("UPDATE_SESSION", () => {
146
- refetchSession();
147
- });
156
+ emitter.off("UPDATE_SESSION", handler);
148
157
  };
149
- }, [conversationId]);
158
+ }, [conversationId, refetchConversationSessions]);
150
159
  useEffect(() => {
151
160
  if (!loadState.hasMoreNew && !loadState.initLoading) {
152
161
  handleMarkConversationMessageAsRead();
@@ -174,7 +183,7 @@ const MessageList = (props) => {
174
183
  backgroundSize: "cover",
175
184
  backgroundPosition: "center",
176
185
  overflowX: "hidden",
177
- }, children: [_jsx(MessageHeader, { onClose: onClose, currentSession: currentSession }), _jsx("div", { id: "scrollableMessagesDiv", ref: scrollRef, style: {
186
+ }, children: [_jsx(MessageHeader, { onClose: onClose, currentSession: latestConversationSession }), _jsx("div", { id: "scrollableMessagesDiv", ref: scrollRef, style: {
178
187
  height: "100%",
179
188
  overflowY: "auto",
180
189
  overflowX: "hidden",
@@ -192,6 +201,6 @@ const MessageList = (props) => {
192
201
  handleMarkConversationMessageAsRead();
193
202
  loadMoreNewMessage();
194
203
  }
195
- }, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array, contextMenuOpen: openMenuId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenMenuId(open ? message.clientMsgID : null), onRevokeMessage: handleOpenRevoke, onQuoteMessage: setQuotedMessage, onPressQuoteMessage: onPressQuoteMessage }, message.clientMsgID))) }) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), _jsx(MessageFooter, { currentSession: currentSession, openCreateCannedModal: openCreateCannedModal }), _jsx(Modal, { centered: true, open: showConfirmRevoke, onOk: onRevokeMessage, onCancel: handleCloseRevoke, title: t("revoke_message_confirm_title"), okText: t("revoke"), cancelText: t("cancel"), okType: "danger", confirmLoading: isRevoking, getContainer: false, forceRender: true, children: _jsx("p", { children: t("revoke_message_confirm_message") }) })] }));
204
+ }, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array, contextMenuOpen: openMenuId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenMenuId(open ? message.clientMsgID : null), onRevokeMessage: handleOpenRevoke, onQuoteMessage: setQuotedMessage, onPressQuoteMessage: onPressQuoteMessage }, message.clientMsgID))) }) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), isNotGroupMember ? (_jsxs("div", { className: "border-t bg-white py-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-sm text-gray-500", children: t("join_group_required") }), _jsx(Button, { type: "primary", onClick: handleJoinGroup, loading: isJoining, children: t("join_group") })] })) : (_jsx(MessageFooter, { currentSession: latestConversationSession, openCreateCannedModal: openCreateCannedModal })), _jsx(Modal, { centered: true, open: showConfirmRevoke, onOk: onRevokeMessage, onCancel: handleCloseRevoke, title: t("revoke_message_confirm_title"), okText: t("revoke"), cancelText: t("cancel"), okType: "danger", confirmLoading: isRevoking, getContainer: false, forceRender: true, children: _jsx("p", { children: t("revoke_message_confirm_message") }) })] }));
196
205
  };
197
206
  export default MessageList;
@@ -1 +1 @@
1
- {"version":3,"file":"SelectSession.d.ts","sourceRoot":"","sources":["../../../src/components/message/SelectSession.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,UAAU,kBAAkB;IAC1B,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IACxD,cAAc,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,QAAA,MAAM,aAAa,GAAI,4DAMpB,kBAAkB,4CAwDpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"SelectSession.d.ts","sourceRoot":"","sources":["../../../src/components/message/SelectSession.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D,UAAU,kBAAkB;IAC1B,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,mBAAmB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IACxD,cAAc,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,QAAA,MAAM,aAAa,GAAI,4DAMpB,kBAAkB,4CAwDpB,CAAC;AAEF,eAAe,aAAa,CAAC"}