@droppii-org/chat-sdk 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/dist/components/canned-response/cannedTrigger.d.ts +2 -0
  2. package/dist/components/canned-response/cannedTrigger.d.ts.map +1 -0
  3. package/dist/components/canned-response/cannedTrigger.js +3 -0
  4. package/dist/components/canned-response/insertCannedContent.js +2 -2
  5. package/dist/components/conversation/ConversationByGroupItem.js +1 -1
  6. package/dist/components/conversation/ConversationBySessionItem.js +4 -4
  7. package/dist/components/conversation/internalNotePreview.d.ts +1 -1
  8. package/dist/components/conversation/internalNotePreview.d.ts.map +1 -1
  9. package/dist/components/conversation/internalNotePreview.js +22 -3
  10. package/dist/components/conversation/rowTime.d.ts +2 -2
  11. package/dist/components/conversation/rowTime.d.ts.map +1 -1
  12. package/dist/components/conversation/rowTime.js +2 -4
  13. package/dist/components/conversation-detail/ConversationDetailInput.d.ts.map +1 -1
  14. package/dist/components/conversation-detail/ConversationDetailInput.js +8 -3
  15. package/dist/components/conversation-detail/ConversationMessageList.d.ts.map +1 -1
  16. package/dist/components/conversation-detail/ConversationMessageList.js +7 -4
  17. package/dist/components/conversation-detail/bot/BotMenuSheet.d.ts.map +1 -1
  18. package/dist/components/conversation-detail/bot/BotMenuSheet.js +1 -1
  19. package/dist/components/conversation-inbox/ConversationInboxList.d.ts.map +1 -1
  20. package/dist/components/conversation-inbox/ConversationInboxList.js +4 -0
  21. package/dist/components/conversation-inbox/InboxBootStatus.d.ts.map +1 -1
  22. package/dist/components/conversation-inbox/InboxBootStatus.js +10 -2
  23. package/dist/components/group/CreateGroupForm.d.ts.map +1 -1
  24. package/dist/components/group/CreateGroupForm.js +2 -1
  25. package/dist/components/group/CreateGroupFormCrmView.d.ts.map +1 -1
  26. package/dist/components/group/CreateGroupFormCrmView.js +1 -1
  27. package/dist/components/group/GroupMemberPickerCrm.d.ts.map +1 -1
  28. package/dist/components/group/GroupMemberPickerCrm.js +1 -1
  29. package/dist/components/media-collection/FileCollection.d.ts.map +1 -1
  30. package/dist/components/media-collection/FileCollection.js +2 -1
  31. package/dist/components/media-collection/ImageCollection.d.ts.map +1 -1
  32. package/dist/components/media-collection/ImageCollection.js +2 -1
  33. package/dist/components/media-collection/LinkCollection.d.ts.map +1 -1
  34. package/dist/components/media-collection/LinkCollection.js +14 -26
  35. package/dist/components/media-collection/VideoCollection.d.ts.map +1 -1
  36. package/dist/components/media-collection/VideoCollection.js +2 -1
  37. package/dist/components/media-resources/ResourceScrollContainer.d.ts.map +1 -1
  38. package/dist/components/media-resources/ResourceScrollContainer.js +34 -2
  39. package/dist/components/message/GroupMembersDrawer.d.ts.map +1 -1
  40. package/dist/components/message/GroupMembersDrawer.js +2 -3
  41. package/dist/components/message/MessageList.d.ts.map +1 -1
  42. package/dist/components/message/MessageList.js +16 -5
  43. package/dist/components/message/footer/ActionBar.d.ts.map +1 -1
  44. package/dist/components/message/footer/ActionBar.js +10 -44
  45. package/dist/components/message/footer/CannedResponsePlugin.d.ts.map +1 -1
  46. package/dist/components/message/footer/CannedResponsePlugin.js +3 -2
  47. package/dist/components/message/footer/EnterHandler.d.ts.map +1 -1
  48. package/dist/components/message/footer/EnterHandler.js +10 -47
  49. package/dist/components/message/footer/FilePreview.d.ts.map +1 -1
  50. package/dist/components/message/footer/FilePreview.js +2 -1
  51. package/dist/components/message/footer/LinkInputPreview.d.ts +1 -1
  52. package/dist/components/message/footer/LinkInputPreview.d.ts.map +1 -1
  53. package/dist/components/message/footer/LinkInputPreview.js +8 -1
  54. package/dist/components/message/footer/MediaUploadButtons.d.ts.map +1 -1
  55. package/dist/components/message/footer/MediaUploadButtons.js +4 -7
  56. package/dist/components/message/footer/index.d.ts.map +1 -1
  57. package/dist/components/message/footer/index.js +57 -16
  58. package/dist/components/message/footer/mention/useMentionOptions.d.ts.map +1 -1
  59. package/dist/components/message/footer/mention/useMentionOptions.js +2 -6
  60. package/dist/components/message/footer/resetEditorAfterSend.d.ts +7 -0
  61. package/dist/components/message/footer/resetEditorAfterSend.d.ts.map +1 -0
  62. package/dist/components/message/footer/resetEditorAfterSend.js +62 -0
  63. package/dist/components/message/groupMemberMenuCrm.d.ts +4 -4
  64. package/dist/components/message/groupMemberMenuCrm.d.ts.map +1 -1
  65. package/dist/components/message/groupMemberMenuCrm.js +73 -60
  66. package/dist/components/message/item/SystemLogMessage.d.ts.map +1 -1
  67. package/dist/components/message/item/SystemLogMessage.js +5 -2
  68. package/dist/components/message/item/index.d.ts.map +1 -1
  69. package/dist/components/message/item/index.js +1 -0
  70. package/dist/components/search-conversation/SearchConversationAsGroups.js +1 -1
  71. package/dist/components/search-conversation/SearchConversationAsMessages.js +1 -1
  72. package/dist/components/search-conversation/SearchConversationMyInbox.js +1 -1
  73. package/dist/components/thread/GroupInfoBodyCrm.d.ts.map +1 -1
  74. package/dist/components/thread/GroupInfoBodyCrm.js +2 -2
  75. package/dist/components/thread/GroupThreadInfo.d.ts.map +1 -1
  76. package/dist/components/thread/GroupThreadInfo.js +2 -6
  77. package/dist/components/thread/ManualAssignPopover.d.ts.map +1 -1
  78. package/dist/components/thread/ManualAssignPopover.js +6 -8
  79. package/dist/components/thread/SessionDetailCard.d.ts.map +1 -1
  80. package/dist/components/thread/SessionDetailCard.js +3 -3
  81. package/dist/components/thread/SessionSection.d.ts.map +1 -1
  82. package/dist/components/thread/SessionSection.js +3 -9
  83. package/dist/components/thread/SessionTagPicker.d.ts +3 -1
  84. package/dist/components/thread/SessionTagPicker.d.ts.map +1 -1
  85. package/dist/components/thread/SessionTagPicker.js +2 -2
  86. package/dist/components/thread/sessionDateFormat.d.ts +2 -0
  87. package/dist/components/thread/sessionDateFormat.d.ts.map +1 -1
  88. package/dist/components/thread/sessionDateFormat.js +6 -0
  89. package/dist/constants/dateFormat.d.ts +2 -0
  90. package/dist/constants/dateFormat.d.ts.map +1 -0
  91. package/dist/constants/dateFormat.js +2 -0
  92. package/dist/hooks/common/useFetchUrlMetadata.d.ts +1 -0
  93. package/dist/hooks/common/useFetchUrlMetadata.d.ts.map +1 -1
  94. package/dist/hooks/conversation/useBotFlow.d.ts.map +1 -1
  95. package/dist/hooks/conversation/useBotFlow.js +64 -12
  96. package/dist/hooks/conversation/useCloseBotSession.d.ts +2 -0
  97. package/dist/hooks/conversation/useCloseBotSession.d.ts.map +1 -1
  98. package/dist/hooks/conversation/useCloseBotSession.js +17 -1
  99. package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
  100. package/dist/hooks/global/useGlobalEvent.js +148 -16
  101. package/dist/hooks/global/useLoginHealth.d.ts +3 -0
  102. package/dist/hooks/global/useLoginHealth.d.ts.map +1 -0
  103. package/dist/hooks/global/useLoginHealth.js +55 -0
  104. package/dist/hooks/group/useCreateGroup.d.ts.map +1 -1
  105. package/dist/hooks/group/useCreateGroup.js +75 -6
  106. package/dist/hooks/init/useChatBootPhase.d.ts +2 -0
  107. package/dist/hooks/init/useChatBootPhase.d.ts.map +1 -1
  108. package/dist/hooks/init/useChatBootPhase.js +11 -6
  109. package/dist/hooks/message/useMessage.d.ts.map +1 -1
  110. package/dist/hooks/message/useMessage.js +97 -28
  111. package/dist/hooks/message/usePinMessage.d.ts +2 -1
  112. package/dist/hooks/message/usePinMessage.d.ts.map +1 -1
  113. package/dist/hooks/message/usePinMessage.js +4 -1
  114. package/dist/hooks/message/usePinnedMessages.d.ts.map +1 -1
  115. package/dist/hooks/message/usePinnedMessages.js +13 -2
  116. package/dist/hooks/message/useRevokeMessage.d.ts.map +1 -1
  117. package/dist/hooks/message/useRevokeMessage.js +25 -0
  118. package/dist/hooks/message/useSendMessage.d.ts +15 -12
  119. package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
  120. package/dist/hooks/message/useSendMessage.js +199 -133
  121. package/dist/hooks/search/useSearchMessage.d.ts.map +1 -1
  122. package/dist/hooks/search/useSearchMessage.js +57 -3
  123. package/dist/hooks/session/useConversationSessionState.d.ts.map +1 -1
  124. package/dist/hooks/session/useConversationSessionState.js +4 -1
  125. package/dist/hooks/session/useSessionLatestPreview.d.ts.map +1 -1
  126. package/dist/hooks/session/useSessionLatestPreview.js +34 -4
  127. package/dist/hooks/user/useAuth.d.ts +1 -1
  128. package/dist/hooks/user/useAuth.d.ts.map +1 -1
  129. package/dist/hooks/user/useAuth.js +31 -15
  130. package/dist/index.d.ts +1 -0
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +1 -0
  133. package/dist/locales/vi/boot.json +5 -1
  134. package/dist/locales/vi/common.json +34 -15
  135. package/dist/locales/vi/conversation-inbox.json +2 -1
  136. package/dist/screens/conversation-detail/index.d.ts.map +1 -1
  137. package/dist/screens/conversation-detail/index.js +6 -0
  138. package/dist/screens/desk-message/DeskBootCard.d.ts.map +1 -1
  139. package/dist/screens/desk-message/DeskBootCard.js +6 -4
  140. package/dist/store/boot.d.ts +5 -0
  141. package/dist/store/boot.d.ts.map +1 -1
  142. package/dist/store/boot.js +11 -1
  143. package/dist/store/conversation.d.ts.map +1 -1
  144. package/dist/store/conversation.js +5 -1
  145. package/dist/store/type.d.ts +3 -1
  146. package/dist/store/type.d.ts.map +1 -1
  147. package/dist/styles/global.css +1 -1
  148. package/dist/types/chat.d.ts +1 -1
  149. package/dist/types/chat.d.ts.map +1 -1
  150. package/dist/utils/common.d.ts.map +1 -1
  151. package/dist/utils/common.js +4 -1
  152. package/dist/utils/fileValidation.d.ts +7 -0
  153. package/dist/utils/fileValidation.d.ts.map +1 -1
  154. package/dist/utils/fileValidation.js +37 -13
  155. package/dist/utils/latestMessagePreviewable.d.ts +2 -0
  156. package/dist/utils/latestMessagePreviewable.d.ts.map +1 -0
  157. package/dist/utils/latestMessagePreviewable.js +18 -0
  158. package/dist/utils/mentionMembers.d.ts +3 -0
  159. package/dist/utils/mentionMembers.d.ts.map +1 -0
  160. package/dist/utils/mentionMembers.js +29 -0
  161. package/dist/utils/messageLog.d.ts +2 -2
  162. package/dist/utils/messageLog.d.ts.map +1 -1
  163. package/dist/utils/messageLog.js +129 -40
  164. package/dist/utils/notifiableMessage.d.ts +7 -0
  165. package/dist/utils/notifiableMessage.d.ts.map +1 -0
  166. package/dist/utils/notifiableMessage.js +26 -0
  167. package/dist/utils/withSdkTimeout.d.ts +11 -0
  168. package/dist/utils/withSdkTimeout.d.ts.map +1 -0
  169. package/dist/utils/withSdkTimeout.js +30 -0
  170. package/package.json +1 -1
@@ -6,11 +6,58 @@ import { useTranslation } from "react-i18next";
6
6
  import { GroupType, GroupVerificationType, GroupVisibility, SessionType } from "@droppii-org/wasm-client-sdk";
7
7
  import { DChatSDK } from "../../constants/sdk";
8
8
  import useAuthStore from "../../store/auth";
9
+ import { useChatContext } from "../../context/ChatContext";
9
10
  import { useDeskThreadNavigation } from "../../hooks/conversation/useDeskThreadNavigation";
10
11
  import { generateDefaultGroupName } from "../../utils/groupName";
12
+ import { SdkTimeoutError, withSdkTimeout } from "../../utils/withSdkTimeout";
11
13
  import { QUERY_KEYS } from "../../services/query";
12
14
  const GET_CONVERSATION_RETRY_COUNT = 4;
13
15
  const GET_CONVERSATION_RETRY_DELAY_MS = 500;
16
+ // A create that timed out may still have gone through. Only a group that did not exist
17
+ // before the call and was created since it started (minus clock skew) can be the result.
18
+ const CREATE_TIME_SKEW_MS = 5000;
19
+ const listJoinedGroups = async () => {
20
+ const { data } = await withSdkTimeout(DChatSDK.getJoinedGroupList(), "getJoinedGroupList");
21
+ return data !== null && data !== void 0 ? data : [];
22
+ };
23
+ // Full member IDs when core can list them; null means unknown, so the head count decides.
24
+ const hasExpectedMembers = async (groupID, expectedUserIDs) => {
25
+ try {
26
+ const { data } = await withSdkTimeout(DChatSDK.getGroupMemberList({
27
+ groupID,
28
+ filter: 0,
29
+ offset: 0,
30
+ count: expectedUserIDs.length + 1,
31
+ }), "getGroupMemberList");
32
+ if (!data)
33
+ return null;
34
+ const actual = new Set(data.map((member) => member.userID));
35
+ return (actual.size === expectedUserIDs.length &&
36
+ expectedUserIDs.every((userID) => actual.has(userID)));
37
+ }
38
+ catch (_a) {
39
+ return null;
40
+ }
41
+ };
42
+ const findRecentlyCreatedGroup = async ({ name, ownerUserID, memberUserIDs, since, knownGroupIDs, }) => {
43
+ try {
44
+ const expectedUserIDs = [...new Set([ownerUserID, ...memberUserIDs])];
45
+ const candidates = (await listJoinedGroups()).filter((group) => !knownGroupIDs.has(group.groupID) &&
46
+ group.groupName === name &&
47
+ group.ownerUserID === ownerUserID &&
48
+ group.memberCount === expectedUserIDs.length &&
49
+ group.createTime >= since - CREATE_TIME_SKEW_MS);
50
+ for (const group of candidates) {
51
+ if ((await hasExpectedMembers(group.groupID, expectedUserIDs)) !== false)
52
+ return group;
53
+ }
54
+ return undefined;
55
+ }
56
+ catch (error) {
57
+ console.warn("find recently created group", error);
58
+ return undefined;
59
+ }
60
+ };
14
61
  const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
15
62
  // createGroup()'s own response succeeding doesn't mean the local WASM store
16
63
  // has the new conversation yet — the WS event that inserts it locally can
@@ -21,10 +68,10 @@ const getOneConversationWithRetry = async (groupID) => {
21
68
  let lastError;
22
69
  for (let attempt = 0; attempt < GET_CONVERSATION_RETRY_COUNT; attempt++) {
23
70
  try {
24
- return await DChatSDK.getOneConversation({
71
+ return await withSdkTimeout(DChatSDK.getOneConversation({
25
72
  sourceID: groupID,
26
73
  sessionType: SessionType.Group,
27
- });
74
+ }), "getOneConversation");
28
75
  }
29
76
  catch (error) {
30
77
  lastError = error;
@@ -46,13 +93,14 @@ export const useCreateGroup = () => {
46
93
  const { openThread } = useDeskThreadNavigation();
47
94
  const queryClient = useQueryClient();
48
95
  const userID = useAuthStore((state) => state.userID);
96
+ const { user } = useChatContext();
49
97
  const createGroup = useCallback(async ({ groupName, isPublic, members, faceURL }) => {
50
98
  var _a, _b;
51
99
  const trimmedName = groupName.trim();
52
100
  const [firstMember, ...restMembers] = members;
53
101
  const resolvedName = trimmedName ||
54
102
  generateDefaultGroupName({
55
- creatorName: tCommon("you"),
103
+ creatorName: (user === null || user === void 0 ? void 0 : user.nickname) || tCommon("you"),
56
104
  firstMemberName: firstMember === null || firstMember === void 0 ? void 0 : firstMember.displayName,
57
105
  remainingCount: restMembers.length,
58
106
  });
@@ -60,7 +108,13 @@ export const useCreateGroup = () => {
60
108
  // group image (DROPPII-30928).
61
109
  const resolvedFaceURL = faceURL || "";
62
110
  try {
63
- const { data: group } = await DChatSDK.createGroup({
111
+ // Without a snapshot a pre-existing twin cannot be told apart, so the fallback stays off.
112
+ const knownGroupIDs = await listJoinedGroups()
113
+ .then((groups) => new Set(groups.map((group) => group.groupID)))
114
+ .catch(() => null);
115
+ const startedAt = Date.now();
116
+ // A stalled core call must end in the error toast, not a dialog stuck on "loading".
117
+ const { groupID } = await withSdkTimeout(DChatSDK.createGroup({
64
118
  memberUserIDs: members.map((member) => member.userID),
65
119
  ownerUserID: userID,
66
120
  groupInfo: {
@@ -71,8 +125,23 @@ export const useCreateGroup = () => {
71
125
  ex: JSON.stringify({ isPublic }),
72
126
  visibility: isPublic ? GroupVisibility.Public : GroupVisibility.Private,
73
127
  },
128
+ }), "createGroup").then(({ data }) => data, async (error) => {
129
+ if (!(error instanceof SdkTimeoutError))
130
+ throw error;
131
+ const created = knownGroupIDs
132
+ ? await findRecentlyCreatedGroup({
133
+ name: resolvedName,
134
+ ownerUserID: userID,
135
+ memberUserIDs: members.map((member) => member.userID),
136
+ since: startedAt,
137
+ knownGroupIDs,
138
+ })
139
+ : undefined;
140
+ if (!created)
141
+ throw error;
142
+ return created;
74
143
  });
75
- const { data: conversation } = await getOneConversationWithRetry(group.groupID);
144
+ const { data: conversation } = await getOneConversationWithRetry(groupID);
76
145
  message.success(t("create_group.create_group_success"));
77
146
  void queryClient.invalidateQueries({
78
147
  queryKey: [QUERY_KEYS.GET_CONVERSATION_GROUPS],
@@ -87,6 +156,6 @@ export const useCreateGroup = () => {
87
156
  message.error(errorMessage);
88
157
  throw error;
89
158
  }
90
- }, [openThread, t, tCommon, userID, queryClient]);
159
+ }, [openThread, t, tCommon, userID, user === null || user === void 0 ? void 0 : user.nickname, queryClient]);
91
160
  return { createGroup };
92
161
  };
@@ -5,6 +5,8 @@ export interface ChatBootState {
5
5
  phase: ChatBootPhase;
6
6
  /** Step that failed when `phase` is "error". */
7
7
  failedStep: ChatBootFailedStep | null;
8
+ /** The failure is a sign-in from another device, not a network problem. */
9
+ isKicked: boolean;
8
10
  /** 0-100, meaningful in the "sync" phase. */
9
11
  syncProgress: number;
10
12
  /** The current step has run longer than the caller's `slowAfterMs`. */
@@ -1 +1 @@
1
- {"version":3,"file":"useChatBootPhase.d.ts","sourceRoot":"","sources":["../../../src/hooks/init/useChatBootPhase.ts"],"names":[],"mappings":"AAIA,OAAqB,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAE9E,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,aAAa,CAAC;IACrB,gDAAgD;IAChD,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACtC,6CAA6C;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,MAAM,EAAE,OAAO,CAAC;IAChB,oFAAoF;IACpF,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,oFAAoF;AACpF,eAAO,MAAM,aAAa,QAAS,CAAC;AAEpC,UAAU,qBAAqB;IAC7B,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACvC;AAED,eAAO,MAAM,oBAAoB,GAAI,+DAKlC,qBAAqB,KAAG,aAO1B,CAAC;AAEF,iGAAiG;AACjG,eAAO,MAAM,gBAAgB,GAAI,kBAE9B;IACD,WAAW,EAAE,MAAM,CAAC;CACrB,KAAG,aAwDH,CAAC"}
1
+ {"version":3,"file":"useChatBootPhase.d.ts","sourceRoot":"","sources":["../../../src/hooks/init/useChatBootPhase.ts"],"names":[],"mappings":"AAIA,OAAqB,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAE9E,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,aAAa,CAAC;IACrB,gDAAgD;IAChD,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACtC,2EAA2E;IAC3E,QAAQ,EAAE,OAAO,CAAC;IAClB,6CAA6C;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,MAAM,EAAE,OAAO,CAAC;IAChB,oFAAoF;IACpF,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,oBAAoB,MAAM,CAAC;AACxC,oFAAoF;AACpF,eAAO,MAAM,aAAa,QAAS,CAAC;AAEpC,UAAU,qBAAqB;IAC7B,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAAC;CACvC;AAED,eAAO,MAAM,oBAAoB,GAAI,+DAKlC,qBAAqB,KAAG,aAO1B,CAAC;AAEF,iGAAiG;AACjG,eAAO,MAAM,gBAAgB,GAAI,kBAE9B;IACD,WAAW,EAAE,MAAM,CAAC;CACrB,KAAG,aA6DH,CAAC"}
@@ -22,13 +22,17 @@ export const useChatBootPhase = ({ slowAfterMs, }) => {
22
22
  const hasConnected = useBootStore((state) => state.hasConnected);
23
23
  const isFirstSyncDone = useBootStore((state) => state.isFirstSyncDone);
24
24
  const failedStep = useBootStore((state) => state.failedStep);
25
+ const isKicked = useBootStore((state) => state.isKicked);
25
26
  const syncProgress = useBootStore((state) => state.syncProgress);
26
- const basePhase = resolveChatBootPhase({
27
- connectStatus,
28
- hasConnected,
29
- isFirstSyncDone,
30
- failedStep,
31
- });
27
+ // A kick is final even if a later connect event flips the connect status back.
28
+ const basePhase = isKicked
29
+ ? "error"
30
+ : resolveChatBootPhase({
31
+ connectStatus,
32
+ hasConnected,
33
+ isFirstSyncDone,
34
+ failedStep,
35
+ });
32
36
  // Sync progress restarts the slow/stall timers: a moving sync is not stuck.
33
37
  const stepKey = basePhase === "sync" ? `sync:${syncProgress}` : basePhase;
34
38
  const [isDelayOver, setIsDelayOver] = useState(false);
@@ -65,6 +69,7 @@ export const useChatBootPhase = ({ slowAfterMs, }) => {
65
69
  return {
66
70
  phase,
67
71
  failedStep: isStalled ? "connect" : phase === "error" ? failedStep : null,
72
+ isKicked: phase === "error" && isKicked,
68
73
  syncProgress,
69
74
  isSlow: slowStepKey === stepKey,
70
75
  isStatusVisible: isDelayOver || phase === "error",
@@ -1 +1 @@
1
- {"version":3,"file":"useMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useMessage.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,WAAW,EACX,WAAW,EAEZ,MAAM,8BAA8B,CAAC;AAkBtC,eAAO,MAAM,kBAAkB,eAkB9B,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,SAAS,WAAW,EACpB,OAAO,OAAO,EACd,eAAe;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,EAC5E,eAAe,MAAM,KACpB,OA4BF,CAAC;AAEF,eAAO,MAAM,UAAU,GACrB,iBAAiB,MAAM,EACvB,oBAAoB,MAAM,EAC1B,iBAAc,EACd,uBAAqB,EAGrB,yBAAyB,MAAM,IAAI;;;;;qBAed,WAAW,EAAE;;;;;;qBAAb,WAAW,EAAE;;;;;;;uCAwBlB,MAAM;CAmYvB,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,SAAS,WAAW,SACpB,CAAC;AAChC,eAAO,MAAM,gBAAgB,GAAI,SAAS,WAAW,SACpB,CAAC;AAClC,eAAO,MAAM,gBAAgB,GAAI,aAAa,MAAM,SACf,CAAC;AAEtC,eAAO,MAAM,kBAAkB,GAC7B,aAAa,WAAW,EAAE,EAC1B,SAAS,WAAW,EACpB,WAAW,MAAM,GAAG,MAAM,EAC1B,YAAY,CAAC,SAAS,EAAE,WAAW,KAAK,OAAO,KAC9C,WAAW,GAAG,SAqBhB,CAAC;AAMF,eAAO,MAAM,oBAAoB,GAC/B,aAAa,WAAW,EAAE,EAC1B,SAAS,WAAW,EACpB,WAAW,MAAM,GAAG,MAAM,KACzB,WAAW,GAAG,SAQhB,CAAC;AAmBF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,WAAW,EAAE,EACtB,SAAS,WAAW,EAAE,kBAgBvB,CAAC"}
1
+ {"version":3,"file":"useMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useMessage.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,WAAW,EAEX,WAAW,EAEZ,MAAM,8BAA8B,CAAC;AAkBtC,eAAO,MAAM,kBAAkB,eAkB9B,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,SAAS,WAAW,EACpB,OAAO,OAAO,EACd,eAAe;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,EAC5E,eAAe,MAAM,KACpB,OA4BF,CAAC;AAEF,eAAO,MAAM,UAAU,GACrB,iBAAiB,MAAM,EACvB,oBAAoB,MAAM,EAC1B,iBAAc,EACd,uBAAqB,EAGrB,yBAAyB,MAAM,IAAI;;;;;qBAed,WAAW,EAAE;;;;;;qBAAb,WAAW,EAAE;;;;;;;uCA6BlB,MAAM;CAscvB,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,SAAS,WAAW,SACpB,CAAC;AAChC,eAAO,MAAM,gBAAgB,GAAI,SAAS,WAAW,SACpB,CAAC;AAClC,eAAO,MAAM,gBAAgB,GAAI,aAAa,MAAM,SACf,CAAC;AAEtC,eAAO,MAAM,kBAAkB,GAC7B,aAAa,WAAW,EAAE,EAC1B,SAAS,WAAW,EACpB,WAAW,MAAM,GAAG,MAAM,EAC1B,YAAY,CAAC,SAAS,EAAE,WAAW,KAAK,OAAO,KAC9C,WAAW,GAAG,SAqBhB,CAAC;AAMF,eAAO,MAAM,oBAAoB,GAC/B,aAAa,WAAW,EAAE,EAC1B,SAAS,WAAW,EACpB,WAAW,MAAM,GAAG,MAAM,KACzB,WAAW,GAAG,SAQhB,CAAC;AAkCF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,WAAW,EAAE,EACtB,SAAS,WAAW,EAAE,kBAgBvB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { useCallback, useEffect, useRef, useState } from "react";
2
- import { ViewType, MessageType, } from "@droppii-org/wasm-client-sdk";
2
+ import { ViewType, MessageStatus, MessageType, } from "@droppii-org/wasm-client-sdk";
3
3
  import { DChatSDK } from "../../constants/sdk";
4
4
  import { PAGE_SIZE } from "../../constants";
5
5
  import { message as antdMessage } from "antd";
@@ -74,6 +74,10 @@ onSearchMessageRevoked) => {
74
74
  });
75
75
  const latestLoadState = useLatest(loadState);
76
76
  const canLoadRef = useLatest(canLoad);
77
+ // Set once this thread's first load has started; local pushes are accepted
78
+ // from then on even while disconnected.
79
+ const loadedTargetRef = useRef(null);
80
+ const canApplyLocalChanges = () => canLoadRef.current || loadedTargetRef.current !== null;
77
81
  const conversationIdRef = useLatest(conversationId);
78
82
  const useAppHistoryRef = useLatest(useAppHistory);
79
83
  // The load effect resets the list when the conversation or history mode
@@ -269,6 +273,7 @@ onSearchMessageRevoked) => {
269
273
  const fetched = [];
270
274
  let bridged = shown.size === 0;
271
275
  let startClientMsgID = "";
276
+ let reachedEnd = false;
272
277
  for (let page = 0; page < MAX_REFRESH_PAGES; page++) {
273
278
  const params = {
274
279
  count: PAGE_SIZE.large,
@@ -283,6 +288,7 @@ onSearchMessageRevoked) => {
283
288
  return;
284
289
  const newestFirst = data.messageList.toReversed();
285
290
  fetched.push(...newestFirst);
291
+ reachedEnd = Boolean(data.isEnd);
286
292
  if (newestFirst.some((msg) => shown.has(msg.clientMsgID))) {
287
293
  bridged = true;
288
294
  break;
@@ -299,23 +305,75 @@ onSearchMessageRevoked) => {
299
305
  if (!bridged) {
300
306
  if (pageLoadingRef.current)
301
307
  return preState;
302
- return Object.assign(Object.assign({}, preState), { hasMoreOld: true, messageList: fetched });
308
+ return Object.assign(Object.assign({}, preState), { hasMoreOld: true, messageList: withLocalUnsent(fetched, preState.messageList) });
303
309
  }
304
310
  const messageList = mergeLatestMessages(preState.messageList, fetched);
305
- return messageList === preState.messageList
311
+ // An empty list had no older-page cursor yet; take it from the walk.
312
+ const hasMoreOld = shown.size === 0 ? !reachedEnd : preState.hasMoreOld;
313
+ return messageList === preState.messageList &&
314
+ hasMoreOld === preState.hasMoreOld
306
315
  ? preState
307
- : Object.assign(Object.assign({}, preState), { messageList });
316
+ : Object.assign(Object.assign({}, preState), { hasMoreOld, messageList });
308
317
  });
309
318
  };
319
+ // Used when the connection is regained. A jumped-to window cannot be topped
320
+ // up in place, so swap in the newest page while keeping unsent local bubbles.
321
+ const reloadNewestKeepingLocal = async () => {
322
+ const reqConversationID = conversationId;
323
+ const reqUseAppHistory = useAppHistory;
324
+ if (!reqConversationID)
325
+ return;
326
+ const params = {
327
+ count: PAGE_SIZE.large,
328
+ startClientMsgID: "",
329
+ conversationID: reqConversationID,
330
+ viewType: ViewType.History,
331
+ };
332
+ const { data } = reqUseAppHistory
333
+ ? await DChatSDK.getAdvancedHistoryMessageListApp(params)
334
+ : await DChatSDK.getAdvancedHistoryMessageList(params);
335
+ if (isStaleResponse(reqConversationID, reqUseAppHistory))
336
+ return;
337
+ setLoadState((preState) => (Object.assign(Object.assign({}, preState), { initLoading: false, hasMoreOld: !data.isEnd, hasMoreNew: false, messageList: withLocalUnsent(data.messageList.toReversed(), preState.messageList) })));
338
+ };
339
+ // A regain that lands while the first load or a page load is in flight
340
+ // cannot refresh yet; remember it and retry once the load settles.
341
+ const needsCatchUpRef = useRef(false);
342
+ const catchUpAfterReconnect = async () => {
343
+ const state = latestLoadState.current;
344
+ if (!state || !canLoadRef.current)
345
+ return;
346
+ if (state.initLoading || pageLoadingRef.current) {
347
+ needsCatchUpRef.current = true;
348
+ return;
349
+ }
350
+ try {
351
+ if (state.hasMoreNew)
352
+ await reloadNewestKeepingLocal();
353
+ else
354
+ await refreshLatestMessages();
355
+ }
356
+ catch (_a) {
357
+ // Next reconnect or poll tries again.
358
+ }
359
+ };
360
+ useEffect(() => {
361
+ if (!needsCatchUpRef.current)
362
+ return;
363
+ if (loadState.initLoading || moreOldLoading || moreNewLoading)
364
+ return;
365
+ needsCatchUpRef.current = false;
366
+ void catchUpAfterReconnect();
367
+ }, [loadState.initLoading, moreOldLoading, moreNewLoading]);
310
368
  useEffect(() => {
311
369
  const pushNewMessage = (message) => {
312
- var _a, _b;
313
- if (!canLoadRef.current)
370
+ if (!canApplyLocalChanges())
314
371
  return;
315
- if ((_b = (_a = latestLoadState.current) === null || _a === void 0 ? void 0 : _a.messageList) === null || _b === void 0 ? void 0 : _b.find((item) => item.clientMsgID === message.clientMsgID)) {
316
- return;
317
- }
318
372
  setLoadState((preState) => {
373
+ // Checked on the queued state: two pushes can land before a render.
374
+ if (preState.messageList.some((item) => item.clientMsgID === message.clientMsgID)) {
375
+ return preState;
376
+ }
319
377
  // sendTime is assigned once at creation (optimistic or server) and
320
378
  // never changes afterwards, so sorting by it keeps messages in the
321
379
  // right order regardless of network delay or how late seq comes back.
@@ -324,7 +382,7 @@ onSearchMessageRevoked) => {
324
382
  });
325
383
  };
326
384
  const updateOneMessage = (message) => {
327
- if (!canLoadRef.current)
385
+ if (!canApplyLocalChanges())
328
386
  return;
329
387
  setLoadState((preState) => {
330
388
  var _a, _b, _c, _d;
@@ -353,7 +411,7 @@ onSearchMessageRevoked) => {
353
411
  });
354
412
  };
355
413
  const removeOneMessage = (clientMsgID) => {
356
- if (!canLoadRef.current)
414
+ if (!canApplyLocalChanges())
357
415
  return;
358
416
  setLoadState((preState) => (Object.assign(Object.assign({}, preState), { messageList: preState.messageList.filter((msg) => msg.clientMsgID !== clientMsgID) })));
359
417
  };
@@ -366,32 +424,33 @@ onSearchMessageRevoked) => {
366
424
  emitter.off("REMOVE_ONE_MSG", removeOneMessage);
367
425
  };
368
426
  }, []);
427
+ // Reset only when the thread itself changes. Losing the connection must not
428
+ // empty the list, or optimistic Sending/Failed bubbles vanish while offline.
369
429
  useEffect(() => {
370
- if (!canLoad) {
371
- setLoadState({
372
- initLoading: true,
373
- hasMoreOld: true,
374
- hasMoreNew: false,
375
- messageList: [],
376
- });
430
+ loadedTargetRef.current = null;
431
+ setLoadState({
432
+ initLoading: true,
433
+ hasMoreOld: true,
434
+ hasMoreNew: false,
435
+ messageList: [],
436
+ });
437
+ }, [conversationId, searchClientMsgID, userID, useAppHistory, enabled]);
438
+ useEffect(() => {
439
+ if (!canLoad || !conversationId)
377
440
  return;
378
- }
379
- if (!conversationId)
441
+ const targetKey = `${conversationId}:${searchClientMsgID !== null && searchClientMsgID !== void 0 ? searchClientMsgID : ""}`;
442
+ if (loadedTargetRef.current === targetKey) {
443
+ // Back online after a drop: pull whatever arrived meanwhile.
444
+ void catchUpAfterReconnect();
380
445
  return;
446
+ }
447
+ loadedTargetRef.current = targetKey;
381
448
  if (!isEmpty(searchClientMsgID)) {
382
449
  searchMessages();
383
450
  }
384
451
  else {
385
452
  getMoreOldMessages(false);
386
453
  }
387
- return () => {
388
- setLoadState(() => ({
389
- initLoading: true,
390
- hasMoreOld: true,
391
- hasMoreNew: false,
392
- messageList: [],
393
- }));
394
- };
395
454
  }, [conversationId, searchClientMsgID, canLoad, userID, useAppHistory]);
396
455
  return {
397
456
  loadState,
@@ -444,6 +503,16 @@ const removeDuplicateMessages = (messages) => {
444
503
  return true;
445
504
  });
446
505
  };
506
+ // Keeps local Sending/Failed bubbles the server page does not know yet.
507
+ const withLocalUnsent = (fetchedNewestFirst, local) => {
508
+ const known = new Set(fetchedNewestFirst.map((msg) => msg.clientMsgID));
509
+ const unsent = local.filter((msg) => !known.has(msg.clientMsgID) &&
510
+ (msg.status === MessageStatus.Sending ||
511
+ msg.status === MessageStatus.Failed));
512
+ if (unsent.length === 0)
513
+ return fetchedNewestFirst;
514
+ return [...unsent, ...fetchedNewestFirst].sort((a, b) => (b.sendTime || 0) - (a.sendTime || 0));
515
+ };
447
516
  // How far refreshLatestMessages walks back to meet the shown list.
448
517
  const MAX_REFRESH_PAGES = 3;
449
518
  // Server copies replace shown ones whose type changed (a revoke becomes its
@@ -1,5 +1,6 @@
1
+ import { MessageItem } from "@droppii-org/wasm-client-sdk";
1
2
  export declare const usePinMessage: () => {
2
- pinMessage: (conversationID: string, clientMsgID: string) => Promise<void>;
3
+ pinMessage: (conversationID: string, clientMsgID: string, message?: Pick<MessageItem, "isInternal">) => Promise<void>;
3
4
  unpinMessage: (conversationID: string, clientMsgID: string) => Promise<void>;
4
5
  };
5
6
  //# sourceMappingURL=usePinMessage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"usePinMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/usePinMessage.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,aAAa;iCAIC,MAAM,eAAe,MAAM;mCAiB3B,MAAM,eAAe,MAAM;CAkBrD,CAAC"}
1
+ {"version":3,"file":"usePinMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/usePinMessage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAQ3D,eAAO,MAAM,aAAa;iCAKJ,MAAM,eACT,MAAM,YACT,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC;mCAoBpB,MAAM,eAAe,MAAM;CAkBrD,CAAC"}
@@ -7,7 +7,10 @@ import { fetchPinnedMessages } from "./usePinnedMessages";
7
7
  // pinned panel, and ahooks >=3.10 rejects a request whose owner unmounts.
8
8
  export const usePinMessage = () => {
9
9
  const userID = useAuthStore((state) => state.userID);
10
- const pinMessage = useCallback(async (conversationID, clientMsgID) => {
10
+ const pinMessage = useCallback(async (conversationID, clientMsgID, message) => {
11
+ // Internal notes must never be pinned, even if a caller bypasses the menu.
12
+ if (message === null || message === void 0 ? void 0 : message.isInternal)
13
+ return;
11
14
  await DChatSDK.pinMsg({
12
15
  conversationID,
13
16
  clientMsgID,
@@ -1 +1 @@
1
- {"version":3,"file":"usePinnedMessages.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/usePinnedMessages.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,GAAU,gBAAgB,MAAM,kBA2B/D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,gBAAgB,MAAM;;;;CAqBvD,CAAC"}
1
+ {"version":3,"file":"usePinnedMessages.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/usePinnedMessages.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,mBAAmB,GAAU,gBAAgB,MAAM,kBAqC/D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,gBAAgB,MAAM;;;;CAqBvD,CAAC"}
@@ -2,6 +2,7 @@ import { useEffect } from "react";
2
2
  import { DChatSDK } from "../../constants/sdk";
3
3
  import { PAGE_SIZE } from "../../constants";
4
4
  import useConversationStore from "../../store/conversation";
5
+ import useAuthStore from "../../store/auth";
5
6
  export const fetchPinnedMessages = async (conversationID) => {
6
7
  var _a, _b;
7
8
  const { setPinnedMessageData } = useConversationStore.getState();
@@ -17,8 +18,18 @@ export const fetchPinnedMessages = async (conversationID) => {
17
18
  const activeConversationId = selectedConversationId || (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID);
18
19
  if (activeConversationId !== conversationID)
19
20
  return;
20
- const sortedMessageList = [...(data.messageList || [])].sort((first, second) => (second.pinnedTime || 0) - (first.pinnedTime || 0));
21
- setPinnedMessageData(sortedMessageList, data.totalCount || 0, (_a = data.remainingPinCount) !== null && _a !== void 0 ? _a : 0, (_b = data.isEnd) !== null && _b !== void 0 ? _b : true);
21
+ // Only CRM may see internal notes; hide pinned ones from everyone else
22
+ // and take them out of the bar total only; the limit uses backend counts.
23
+ const allPinned = data.messageList || [];
24
+ const visiblePinned = useAuthStore.getState().isCrm
25
+ ? allPinned
26
+ : allPinned.filter((message) => !message.isInternal);
27
+ const hiddenCount = allPinned.length - visiblePinned.length;
28
+ const backendTotal = data.totalCount || 0;
29
+ const sortedMessageList = [...visiblePinned].sort((first, second) => (second.pinnedTime || 0) - (first.pinnedTime || 0));
30
+ setPinnedMessageData(sortedMessageList, Math.max(backendTotal - hiddenCount, 0),
31
+ // Hidden pins still occupy backend slots, so keep the real remaining.
32
+ (_a = data.remainingPinCount) !== null && _a !== void 0 ? _a : 0, (_b = data.isEnd) !== null && _b !== void 0 ? _b : true, backendTotal);
22
33
  }
23
34
  catch (error) {
24
35
  console.error("fetchPinnedMessages failed", error);
@@ -1 +1 @@
1
- {"version":3,"file":"useRevokeMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useRevokeMessage.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,mBAAmB,GAC9B,aAAa,MAAM,EACnB,iBAAiB,MAAM,SAoBxB,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;CAkB5B,CAAC"}
1
+ {"version":3,"file":"useRevokeMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useRevokeMessage.ts"],"names":[],"mappings":"AAwCA,eAAO,MAAM,mBAAmB,GAC9B,aAAa,MAAM,EACnB,iBAAiB,MAAM,SAqBxB,CAAC;AAEF,eAAO,MAAM,gBAAgB;;;CAkB5B,CAAC"}
@@ -4,6 +4,30 @@ import { useRequest } from "ahooks";
4
4
  import { updateOneMessage } from "../../hooks/message/useMessage";
5
5
  import { fetchPinnedMessages } from "../../hooks/message/usePinnedMessages";
6
6
  import useConversationStore from "../../store/conversation";
7
+ // The thread card previews conversation.latestMsg (a JSON string); without this
8
+ // it keeps showing the recalled text until the next conversation refresh.
9
+ const patchRevokedLatestMsg = (clientMsgID) => {
10
+ const { conversationList } = useConversationStore.getState();
11
+ let changed = false;
12
+ const next = conversationList.map((conversation) => {
13
+ if (!conversation.latestMsg)
14
+ return conversation;
15
+ try {
16
+ const latest = JSON.parse(conversation.latestMsg);
17
+ if (latest.clientMsgID !== clientMsgID ||
18
+ latest.contentType === MessageType.RevokeMessage) {
19
+ return conversation;
20
+ }
21
+ changed = true;
22
+ return Object.assign(Object.assign({}, conversation), { latestMsg: JSON.stringify(Object.assign(Object.assign({}, latest), { contentType: MessageType.RevokeMessage })) });
23
+ }
24
+ catch (_a) {
25
+ return conversation;
26
+ }
27
+ });
28
+ if (changed)
29
+ useConversationStore.setState({ conversationList: next });
30
+ };
7
31
  // Shared by the actor's own revoke call (conversationID known upfront) and by
8
32
  // the OnNewRecvMessageRevoked socket handler (conversationID unknown, so we
9
33
  // infer it from whichever conversation currently has this message pinned).
@@ -14,6 +38,7 @@ export const applyRevokedMessage = (clientMsgID, conversationID) => {
14
38
  };
15
39
  updateOneMessage(revokedPatch);
16
40
  useConversationStore.getState().updatePinnedMessage(revokedPatch);
41
+ patchRevokedLatestMsg(clientMsgID);
17
42
  const { selectedConversationId, conversationData, pinnedMessageList } = useConversationStore.getState();
18
43
  const targetConversationId = conversationID || selectedConversationId || (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID);
19
44
  const isRevokedMessagePinned = pinnedMessageList.some((pinnedMessage) => pinnedMessage.clientMsgID === clientMsgID);
@@ -8,24 +8,25 @@ export declare const isMediaResendable: (message: {
8
8
  clientMsgID: string;
9
9
  contentType: number;
10
10
  }) => boolean;
11
- export declare const createTextMessage: (text: string) => Promise<MessageItem | null>;
12
- export declare const createImageMessageByFile: (file: ImageMsgParamsByFile) => Promise<MessageItem | null>;
13
- export declare const createMergerMessage: (mergerMsgParams: MergerMsgParams) => Promise<MessageItem | null>;
14
- export declare const createVideoMessageByFile: (file: VideoMsgParamsByFile) => Promise<MessageItem | null>;
15
- export declare const createFileMessageByFile: (file: FileMsgParamsByFile) => Promise<MessageItem | null>;
11
+ export declare const isSendPending: (clientMsgID: string) => boolean;
12
+ export declare const createTextMessage: (text: string) => Promise<MessageItem>;
13
+ export declare const createImageMessageByFile: (file: ImageMsgParamsByFile) => Promise<MessageItem>;
14
+ export declare const createMergerMessage: (mergerMsgParams: MergerMsgParams) => Promise<MessageItem>;
15
+ export declare const createVideoMessageByFile: (file: VideoMsgParamsByFile) => Promise<MessageItem>;
16
+ export declare const createFileMessageByFile: (file: FileMsgParamsByFile) => Promise<MessageItem>;
16
17
  export declare const AT_ALL_TAG = "AtAllTag";
17
- export declare const createAtTextMessage: (params: AtMsgParams) => Promise<MessageItem | null>;
18
- export declare const createUrlTextMessage: (text: string, urls: string[]) => Promise<MessageItem | null>;
19
- export declare const createStickerMessage: (stickerUrl: string) => Promise<MessageItem | null>;
20
- export declare const createCustomMessageByParams: (params: CustomMsgParams) => Promise<MessageItem | null>;
21
- export declare const createCustomMessage: (payload: CustomMessagePayload) => Promise<MessageItem | null>;
22
- export declare const createQuoteMessage: (text: string, quotedMessage: MessageItem, urls?: string[]) => Promise<MessageItem | null>;
18
+ export declare const createAtTextMessage: (params: AtMsgParams) => Promise<MessageItem>;
19
+ export declare const createUrlTextMessage: (text: string, urls: string[]) => Promise<MessageItem>;
20
+ export declare const createStickerMessage: (stickerUrl: string) => Promise<MessageItem>;
21
+ export declare const createCustomMessageByParams: (params: CustomMsgParams) => Promise<MessageItem>;
22
+ export declare const createCustomMessage: (payload: CustomMessagePayload) => Promise<MessageItem>;
23
+ export declare const createQuoteMessage: (text: string, quotedMessage: MessageItem, urls?: string[]) => Promise<MessageItem>;
23
24
  export type SendMessageScrollEvent = "CHAT_LIST_SCROLL_TO_BOTTOM" | "CONVERSATION_CHAT_SCROLL_TO_BOTTOM_IF_AT_BOTTOM";
24
25
  export interface UseSendMessageOptions {
25
26
  scrollEvent?: SendMessageScrollEvent;
26
27
  }
27
28
  export declare const useSendMessage: (options?: UseSendMessageOptions) => {
28
- sendMergeMessage: ({ richText, plainText, files, currentSession, isInternal, urlMetadata, flow, customMessage, mentions, }: {
29
+ sendMergeMessage: ({ richText, plainText, files, currentSession, isInternal, urlMetadata, flow, customMessage, mentions, onBuilt, }: {
29
30
  richText: string;
30
31
  plainText: string;
31
32
  files?: UploadFile[];
@@ -35,6 +36,8 @@ export declare const useSendMessage: (options?: UseSendMessageOptions) => {
35
36
  flow?: BotFlowMeta;
36
37
  customMessage?: CustomMessagePayload;
37
38
  mentions?: MentionSendPayload;
39
+ /** Called once the bubbles are shown (true) or building them failed (false). */
40
+ onBuilt?: (shown: boolean) => void;
38
41
  }) => Promise<boolean>;
39
42
  sendCustomMessage: (payload: CustomMessagePayload, sendOptions?: {
40
43
  currentSession?: ISessionResponse;
@@ -1 +1 @@
1
- {"version":3,"file":"useSendMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useSendMessage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useSendMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useSendMessage.ts"],"names":[],"mappings":"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"}