@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
@@ -0,0 +1,2 @@
1
+ export declare const CANNED_TRIGGER_BEFORE_CURSOR: RegExp;
2
+ //# sourceMappingURL=cannedTrigger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cannedTrigger.d.ts","sourceRoot":"","sources":["../../../src/components/canned-response/cannedTrigger.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,4BAA4B,QAAqB,CAAC"}
@@ -0,0 +1,3 @@
1
+ // Shortcuts may contain "-" (e.g. "#chao-hoi"); the picker and the insert step
2
+ // must agree on the same pattern or the typed trigger is left behind.
3
+ export const CANNED_TRIGGER_BEFORE_CURSOR = /(^|\s)#([\w-]*)$/;
@@ -1,6 +1,6 @@
1
1
  import { $createParagraphNode, $getRoot, $getSelection, $isRangeSelection, $isTextNode, } from "lexical";
2
2
  import { $generateNodesFromDOM } from "@lexical/html";
3
- const TRIGGER_BEFORE_CURSOR = /(^|\s)#\w*$/;
3
+ import { CANNED_TRIGGER_BEFORE_CURSOR } from "./cannedTrigger";
4
4
  // Drops the "#shortcut" the agent typed to open the picker, so only the reply stays.
5
5
  const $removeTriggerBeforeCursor = () => {
6
6
  const selection = $getSelection();
@@ -10,7 +10,7 @@ const $removeTriggerBeforeCursor = () => {
10
10
  const node = anchor.getNode();
11
11
  if (!$isTextNode(node))
12
12
  return;
13
- const match = node.getTextContent().slice(0, anchor.offset).match(TRIGGER_BEFORE_CURSOR);
13
+ const match = node.getTextContent().slice(0, anchor.offset).match(CANNED_TRIGGER_BEFORE_CURSOR);
14
14
  if (!match)
15
15
  return;
16
16
  const triggerStart = anchor.offset - match[0].replace(/^\s/, "").length;
@@ -32,7 +32,7 @@ const ConversationByGroupItem = ({ group, latestPreview, }) => {
32
32
  conversationType: conversation.conversationType,
33
33
  showName: conversation.showName,
34
34
  }), mentionIndicator: _jsx(MentionIndicatorIcon, { groupAtType: conversation.groupAtType }), time: latestMsgSendTime > 0
35
- ? formatListRowTime(latestMsgSendTime, t)
35
+ ? formatListRowTime(latestMsgSendTime)
36
36
  : undefined, avatar: _jsx(GroupAvatar, { faceURL: conversation.faceURL, groupName: conversation.showName, size: 40 }), name: conversation.showName, meta: group.visibility === GroupVisibility.Private ? (_jsxs(RowChip, { tone: "primary", children: [_jsx(StrokeIcon, { name: "lock", size: 14 }), t("group_visibility_private")] })) : undefined }));
37
37
  };
38
38
  export default ConversationByGroupItem;
@@ -57,7 +57,7 @@ const ConversationBySessionItem = ({ sessionItem, latestPreview, folderTag, }) =
57
57
  }
58
58
  : null);
59
59
  const fullTitle = (_j = ownerIdentity === null || ownerIdentity === void 0 ? void 0 : ownerIdentity.displayName) !== null && _j !== void 0 ? _j : displayName;
60
- const { name } = splitDisplayName(fullTitle);
60
+ const { name: avatarName } = splitDisplayName(fullTitle);
61
61
  const latestMsg = (latestPreview === null || latestPreview === void 0 ? void 0 : latestPreview.latestMsg) || "";
62
62
  const latestMsgSendTime = (latestPreview === null || latestPreview === void 0 ? void 0 : latestPreview.latestMsgSendTime) || 0;
63
63
  if (!conversation)
@@ -67,8 +67,8 @@ const ConversationBySessionItem = ({ sessionItem, latestPreview, folderTag, }) =
67
67
  peerType: conversation.peerType,
68
68
  conversationType: conversation.conversationType,
69
69
  showName: conversation.showName,
70
- }), mentionIndicator: _jsx(MentionIndicatorIcon, { groupAtType: conversation.groupAtType }), time: latestMsgSendTime > 0
71
- ? formatListRowTime(latestMsgSendTime, t)
72
- : undefined, avatar: !ownerIdentity && isGroupConversation(conversation) ? (_jsx(GroupAvatar, { faceURL: avatar, groupName: displayName, size: 40 })) : (_jsx(DeskRowAvatar, { name: name, src: ownerIdentity ? ownerIdentity.avatarUrl : avatar })), name: name, nameTooltip: fullTitle, meta: tagChip ? (_jsx(RowChip, { tone: tagChip.tone, children: t(tagChip.labelKey) })) : undefined }));
70
+ }, sessionItem.ownerId || (owner === null || owner === void 0 ? void 0 : owner.id)), mentionIndicator: _jsx(MentionIndicatorIcon, { groupAtType: conversation.groupAtType }), time: latestMsgSendTime > 0
71
+ ? formatListRowTime(latestMsgSendTime)
72
+ : undefined, avatar: !ownerIdentity && isGroupConversation(conversation) ? (_jsx(GroupAvatar, { faceURL: avatar, groupName: displayName, size: 40 })) : (_jsx(DeskRowAvatar, { name: avatarName, src: ownerIdentity ? ownerIdentity.avatarUrl : avatar })), name: fullTitle, nameTooltip: fullTitle, meta: tagChip ? (_jsx(RowChip, { tone: tagChip.tone, children: t(tagChip.labelKey) })) : undefined }));
73
73
  };
74
74
  export default ConversationBySessionItem;
@@ -1,6 +1,6 @@
1
1
  import type { TFunction } from "i18next";
2
2
  import { parseLatestMessage } from "../../utils/common";
3
3
  type PreviewConversation = Parameters<typeof parseLatestMessage>[3];
4
- export declare const buildSessionPreview: (latestMsg: string, userId: string | undefined, t: TFunction, conversation: PreviewConversation) => string;
4
+ export declare const buildSessionPreview: (latestMsg: string, userId: string | undefined, t: TFunction, conversation: PreviewConversation, customerId?: string) => string;
5
5
  export {};
6
6
  //# sourceMappingURL=internalNotePreview.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"internalNotePreview.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/internalNotePreview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAA2B,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAE7E,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;AAGpE,eAAO,MAAM,mBAAmB,GAC9B,WAAW,MAAM,EACjB,QAAQ,MAAM,GAAG,SAAS,EAC1B,GAAG,SAAS,EACZ,cAAc,mBAAmB,KAChC,MAQF,CAAC"}
1
+ {"version":3,"file":"internalNotePreview.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/internalNotePreview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAA2B,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAG7E,KAAK,mBAAmB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;AAcpE,eAAO,MAAM,mBAAmB,GAC9B,WAAW,MAAM,EACjB,QAAQ,MAAM,GAAG,SAAS,EAC1B,GAAG,SAAS,EACZ,cAAc,mBAAmB,EACjC,aAAa,MAAM,KAClB,MAaF,CAAC"}
@@ -1,8 +1,27 @@
1
1
  import { isInternalLatestMessage, parseLatestMessage } from "../../utils/common";
2
- // Desk list only: an internal note reads "Tin nhắn nội bộ: …" instead of a sender name.
3
- export const buildSessionPreview = (latestMsg, userId, t, conversation) => {
2
+ import { isGroupConversation } from "../../utils/imCommon";
3
+ const isFromCustomer = (latestMsg, customerId) => {
4
+ var _a;
5
+ if (!customerId)
6
+ return false;
7
+ try {
8
+ return ((_a = JSON.parse(latestMsg)) === null || _a === void 0 ? void 0 : _a.sendID) === customerId;
9
+ }
10
+ catch (_b) {
11
+ return false;
12
+ }
13
+ };
14
+ // Desk list only: an internal note reads "Tin nhắn nội bộ: …" instead of a sender name,
15
+ // and a message from the customer reads "Khách hàng: …". A group-type session already
16
+ // names the sender in the preview, so the customer label is only added for 1:1 and bot sessions.
17
+ export const buildSessionPreview = (latestMsg, userId, t, conversation, customerId) => {
4
18
  if (!isInternalLatestMessage(latestMsg)) {
5
- return parseLatestMessage(latestMsg, userId, t, conversation);
19
+ const preview = parseLatestMessage(latestMsg, userId, t, conversation);
20
+ return preview &&
21
+ !isGroupConversation(conversation) &&
22
+ isFromCustomer(latestMsg, customerId)
23
+ ? `${t("customer")}: ${preview}`
24
+ : preview;
6
25
  }
7
26
  const text = parseLatestMessage(latestMsg, userId, t, conversation, {
8
27
  includeSenderPrefix: false,
@@ -1,4 +1,4 @@
1
1
  import dayjs from "dayjs";
2
- /** List row time: "HH:mm" today, "Hôm qua" yesterday, otherwise "DD/MM" (with the year when it differs). */
3
- export declare const formatListRowTime: (timestamp: number, t: (key: string) => string, now?: dayjs.Dayjs) => string;
2
+ /** List row time: "HH:mm" today, otherwise "DD/MM" (with the year when it differs). Yesterday has no special name. */
3
+ export declare const formatListRowTime: (timestamp: number, now?: dayjs.Dayjs) => string;
4
4
  //# sourceMappingURL=rowTime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rowTime.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/rowTime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,4GAA4G;AAC5G,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,EACjB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EAC1B,MAAK,KAAK,CAAC,KAAe,KACzB,MAKF,CAAC"}
1
+ {"version":3,"file":"rowTime.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/rowTime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,sHAAsH;AACtH,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,EACjB,MAAK,KAAK,CAAC,KAAe,KACzB,MAIF,CAAC"}
@@ -1,10 +1,8 @@
1
1
  import dayjs from "dayjs";
2
- /** List row time: "HH:mm" today, "Hôm qua" yesterday, otherwise "DD/MM" (with the year when it differs). */
3
- export const formatListRowTime = (timestamp, t, now = dayjs()) => {
2
+ /** List row time: "HH:mm" today, otherwise "DD/MM" (with the year when it differs). Yesterday has no special name. */
3
+ export const formatListRowTime = (timestamp, now = dayjs()) => {
4
4
  const date = dayjs(timestamp);
5
5
  if (date.isSame(now, "day"))
6
6
  return date.format("HH:mm");
7
- if (date.isSame(now.subtract(1, "day"), "day"))
8
- return t("yesterday");
9
7
  return date.format(date.isSame(now, "year") ? "DD/MM" : "DD/MM/YYYY");
10
8
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAoB/D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,wEAAwE;IACxE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACpE;AAED,QAAA,MAAM,uBAAuB,GAAI,8GAQ9B,4BAA4B,4CAm0B9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
1
+ {"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAoB/D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,wEAAwE;IACxE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACpE;AAED,QAAA,MAAM,uBAAuB,GAAI,8GAQ9B,4BAA4B,4CAs0B9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -347,7 +347,9 @@ const ConversationDetailInput = ({ placeholder, onSendMessage, onInputChange, mo
347
347
  };
348
348
  const handleSend = async () => {
349
349
  const text = value.trim();
350
- if ((!text && !hasFiles) || isSending)
350
+ // Text sends are serialized by the send queue, so only an upload still
351
+ // in flight blocks another send; otherwise rapid Enters get swallowed.
352
+ if ((!text && !hasFiles) || (hasFiles && isSending))
351
353
  return;
352
354
  const filesToSend = listUploadFiles;
353
355
  const urlMetadata = showLinkPreview && previewUrl && previewMetadata
@@ -360,7 +362,9 @@ const ConversationDetailInput = ({ placeholder, onSendMessage, onInputChange, mo
360
362
  : undefined;
361
363
  const mentions = mentionTokens.length > 0 ? buildMentionPayload(mentionTokens) : undefined;
362
364
  resetComposer();
363
- setIsSending(true);
365
+ const isUploadSend = filesToSend.length > 0;
366
+ if (isUploadSend)
367
+ setIsSending(true);
364
368
  try {
365
369
  if (onSendMessage) {
366
370
  onSendMessage(text);
@@ -380,7 +384,8 @@ const ConversationDetailInput = ({ placeholder, onSendMessage, onInputChange, mo
380
384
  console.error("handleSend", error);
381
385
  }
382
386
  finally {
383
- setIsSending(false);
387
+ if (isUploadSend)
388
+ setIsSending(false);
384
389
  }
385
390
  };
386
391
  const handleFocus = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationMessageList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAkCf,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,uBAAuB,GAAI,4DAI9B,4BAA4B,4CAoS9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
1
+ {"version":3,"file":"ConversationMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationMessageList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAkCf,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,uBAAuB,GAAI,4DAI9B,4BAA4B,4CA0S9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -82,15 +82,16 @@ const ConversationMessageList = ({ bottomSlot, onCopyMessageLink, onSearchMessag
82
82
  }, []);
83
83
  const { pinMessage, unpinMessage } = usePinMessage();
84
84
  const pinnedTotalCount = useConversationStore((state) => state.pinnedTotalCount);
85
+ const pinnedBackendTotalCount = useConversationStore((state) => state.pinnedBackendTotalCount);
85
86
  const pinnedRemainingCount = useConversationStore((state) => state.pinnedRemainingCount);
86
87
  const [pinLimitModalOpen, setPinLimitModalOpen] = useState(false);
87
88
  const handlePinMessage = useCallback(async (message) => {
88
- if (pinnedRemainingCount <= 0 && pinnedTotalCount > 0) {
89
+ if (pinnedRemainingCount <= 0 && pinnedBackendTotalCount > 0) {
89
90
  setPinLimitModalOpen(true);
90
91
  return;
91
92
  }
92
93
  try {
93
- await pinMessage(conversationId, message.clientMsgID);
94
+ await pinMessage(conversationId, message.clientMsgID, message);
94
95
  toastMessage.success(tCommon("pin_message_success"));
95
96
  }
96
97
  catch (_a) {
@@ -100,7 +101,7 @@ const ConversationMessageList = ({ bottomSlot, onCopyMessageLink, onSearchMessag
100
101
  conversationId,
101
102
  pinMessage,
102
103
  pinnedRemainingCount,
103
- pinnedTotalCount,
104
+ pinnedBackendTotalCount,
104
105
  tCommon,
105
106
  ]);
106
107
  const handleUnpinMessage = useCallback(async (message) => {
@@ -158,7 +159,9 @@ const ConversationMessageList = ({ bottomSlot, onCopyMessageLink, onSearchMessag
158
159
  target: scrollRef,
159
160
  enable: !!openToolboxMessageId,
160
161
  });
161
- return (_jsxs("div", { "data-testid": "conversation-message-list", "data-cp-name": "ConversationMessageList", className: "relative flex min-h-0 min-w-0 flex-1 flex-col overflow-x-hidden bg-white", children: [isMessageLoading ? (_jsx("div", { className: "flex flex-1 items-center justify-center py-12", children: _jsx(Spin, {}) })) : (_jsxs(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableConversationMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, containerClassName: "h-full", empty: _jsx("div", { className: "flex flex-1 items-center justify-center py-12", children: _jsx(Empty, { description: t("empty.no_messages") }) }), children: [_jsx("div", { "aria-hidden": "true", className: "h-3 shrink-0" }), bottomSlot, _jsx(ConsultantCtaContext.Provider, { value: consultantCta, children: loadState.messageList.map((message, index, array) => (_jsx(MessageItem, { message: message, allMessages: array, isGroupChat: isGroupChat, forceHideTip: index === 0 && !!bottomSlot, contextMenuOpen: openToolboxMessageId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenToolboxMessageId(open ? message.clientMsgID : null), onQuoteMessage: canReply ? setQuotedMessage : undefined, onRevokeMessage: handleRevokeMessage, timeRevealed: revealedTimeMsgId === message.clientMsgID, onToggleTimeReveal: handleToggleTimeReveal, onPressQuoteMessage: onPressQuoteMessage, onPinMessage: canPinMessage ? handlePinMessage : undefined, onUnpinMessage: canPinMessage ? handleUnpinMessage : undefined, onCopyMessageLink: onCopyMessageLink ? handleCopyMessageLink : undefined, showUnreadDivider: !!unreadDividerMessageId &&
162
+ return (_jsxs("div", { "data-testid": "conversation-message-list", "data-cp-name": "ConversationMessageList", className: "relative flex min-h-0 min-w-0 flex-1 flex-col overflow-x-hidden bg-white", children: [isMessageLoading ? (_jsx("div", { className: "flex flex-1 items-center justify-center py-12", children: _jsx(Spin, {}) })) : (_jsxs(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableConversationMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, containerClassName: "h-full",
163
+ // An empty thread must still render bottomSlot (bot buttons / start CTA).
164
+ empty: bottomSlot ? undefined : (_jsx("div", { className: "flex flex-1 items-center justify-center py-12", children: _jsx(Empty, { description: t("empty.no_messages") }) })), children: [_jsx("div", { "aria-hidden": "true", className: "h-3 shrink-0" }), bottomSlot, _jsx(ConsultantCtaContext.Provider, { value: consultantCta, children: loadState.messageList.map((message, index, array) => (_jsx(MessageItem, { message: message, allMessages: array, isGroupChat: isGroupChat, forceHideTip: index === 0 && !!bottomSlot, contextMenuOpen: openToolboxMessageId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenToolboxMessageId(open ? message.clientMsgID : null), onQuoteMessage: canReply ? setQuotedMessage : undefined, onRevokeMessage: handleRevokeMessage, timeRevealed: revealedTimeMsgId === message.clientMsgID, onToggleTimeReveal: handleToggleTimeReveal, onPressQuoteMessage: onPressQuoteMessage, onPinMessage: canPinMessage ? handlePinMessage : undefined, onUnpinMessage: canPinMessage ? handleUnpinMessage : undefined, onCopyMessageLink: onCopyMessageLink ? handleCopyMessageLink : undefined, showUnreadDivider: !!unreadDividerMessageId &&
162
165
  message.clientMsgID === unreadDividerMessageId, onUnreadDividerSeen: markDividerSeen, enableLongPress: true }, message.clientMsgID))) })] })), !isMessageLoading && showJumpButton && (_jsx(UnreadMessageJumpButton, { className: "absolute right-0 top-4 z-10", onClick: handleJumpToFirstUnread })), _jsx(PinLimitModal, { open: pinLimitModalOpen, max: pinnedTotalCount, onClose: () => setPinLimitModalOpen(false) })] }));
163
166
  };
164
167
  export default ConversationMessageList;
@@ -1 +1 @@
1
- {"version":3,"file":"BotMenuSheet.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/BotMenuSheet.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAI5D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;CAC3C;AAED,QAAA,MAAM,YAAY,GAAI,+CAMnB,iBAAiB,4CAmEnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"BotMenuSheet.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/BotMenuSheet.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAI5D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;CAC3C;AAED,QAAA,MAAM,YAAY,GAAI,+CAMnB,iBAAiB,4CAwEnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -17,7 +17,7 @@ const BotMenuSheet = ({ open, items, disabled, onClose, onSelect, }) => {
17
17
  body: { padding: "16px 16px 32px" },
18
18
  mask: { backgroundColor: "rgba(0, 0, 0, 0.8)" },
19
19
  content: { background: "transparent", boxShadow: "none" },
20
- }, getContainer: false, forceRender: true, children: _jsxs("div", { className: "flex flex-col overflow-hidden rounded-2xl bg-white", children: [_jsxs("div", { className: "flex items-center gap-4 border-b border-gray-25 px-3 py-4", children: [_jsx("span", { className: "flex-1 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("thread_detail.bot.menu.title") }), _jsx(Button, { type: "text", shape: "default", className: "!h-6 !w-6 !p-0 text-gray-900", onClick: onClose, "aria-label": t("thread_detail.bot.menu.title"), children: _jsx(Icon, { icon: "close-b", size: 24 }) })] }), _jsx("div", { className: "flex flex-col", children: items.map((item, index) => (_jsxs("button", { type: "button", disabled: disabled, onClick: () => handleSelect(item), className: "flex items-center gap-4 border-b border-gray-25 px-3 py-3 text-left transition-colors last:border-b-0 disabled:cursor-not-allowed disabled:opacity-60", children: [_jsx("span", { className: "flex-1 text-[16px] font-medium leading-[1.6] text-gray-900", children: item.id === BOT_DEFAULT_BUTTON_ID
20
+ }, getContainer: false, forceRender: true, children: _jsxs("div", { className: "flex flex-col overflow-hidden rounded-2xl bg-white", children: [_jsxs("div", { className: "flex items-center gap-4 border-b border-gray-25 px-3 py-4", children: [_jsxs("div", { className: "flex flex-1 flex-col", children: [_jsx("span", { className: "text-[18px] font-bold leading-[1.6] text-gray-900", children: t("thread_detail.bot.menu.title") }), _jsx("span", { className: "text-[14px] leading-[1.6] text-gray-500", children: t("thread_detail.bot.menu.description") })] }), _jsx(Button, { type: "text", shape: "default", className: "!h-6 !w-6 !p-0 text-gray-900", onClick: onClose, "aria-label": t("thread_detail.bot.menu.title"), children: _jsx(Icon, { icon: "close-b", size: 24 }) })] }), _jsx("div", { className: "flex flex-col", children: items.map((item, index) => (_jsxs("button", { type: "button", disabled: disabled, onClick: () => handleSelect(item), className: "flex items-center gap-4 border-b border-gray-25 px-3 py-3 text-left transition-colors last:border-b-0 disabled:cursor-not-allowed disabled:opacity-60", children: [_jsx("span", { className: "flex-1 text-[16px] font-medium leading-[1.6] text-gray-900", children: item.id === BOT_DEFAULT_BUTTON_ID
21
21
  ? t("thread_detail.bot.restart")
22
22
  : item.label }), _jsx(Icon, { icon: "angle-right-o", size: CHEVRON_SIZE, className: "text-gray-900" })] }, `${item.id}-${index}`))) })] }) }));
23
23
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationInboxList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/ConversationInboxList.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAYjE,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,oBAAoB,EAAE,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACtD,oDAAoD;IACpD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAYD,QAAA,MAAM,qBAAqB,GAAI,mGAQ5B,0BAA0B,4CA+F5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"ConversationInboxList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/ConversationInboxList.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAYjE,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,oBAAoB,EAAE,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACtD,oDAAoD;IACpD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAYD,QAAA,MAAM,qBAAqB,GAAI,mGAQ5B,0BAA0B,4CA2G5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -36,6 +36,10 @@ const ConversationInboxList = ({ items, isLoading, isFetchingNextPage, hasNextPa
36
36
  onLoadMore();
37
37
  }
38
38
  };
39
+ // Signed in elsewhere: the list is stale and cannot refresh, whatever the boot phase.
40
+ if (boot.isKicked) {
41
+ return (_jsx("div", { "data-testid": "conversation-inbox-thread-list", className: "min-h-0 w-full flex-1 overflow-hidden", children: _jsx(InboxBootStatus, { boot: boot }) }));
42
+ }
39
43
  // Until the list has loaded once after the first sync, an empty list means "not loaded yet".
40
44
  if (items.length === 0 && (!isListSettled || isLoading)) {
41
45
  return (_jsxs("div", { "data-testid": "conversation-inbox-thread-list", className: "min-h-0 w-full flex-1 overflow-hidden", children: [!isListSettled && (_jsx(InboxBootStatus, { boot: boot.phase === "ready"
@@ -1 +1 @@
1
- {"version":3,"file":"InboxBootStatus.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/InboxBootStatus.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAyCnE;;;GAGG;AACH,QAAA,MAAM,eAAe,GAAI,UAAU;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,mDAmDzD,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"InboxBootStatus.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/InboxBootStatus.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAyCnE;;;GAGG;AACH,QAAA,MAAM,eAAe,GAAI,UAAU;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,mDA2DzD,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -27,8 +27,16 @@ const InboxBootStatus = ({ boot }) => {
27
27
  if (boot.phase === "ready")
28
28
  return null;
29
29
  const isError = boot.phase === "error";
30
- const title = isError ? t("inbox.error_title") : t("inbox.title");
31
- const detail = isError ? t("inbox.error_hint") : t(`inbox.${boot.phase}`);
30
+ const title = boot.isKicked
31
+ ? t("inbox.kicked_title")
32
+ : isError
33
+ ? t("inbox.error_title")
34
+ : t("inbox.title");
35
+ const detail = boot.isKicked
36
+ ? t("inbox.kicked_hint")
37
+ : isError
38
+ ? t("inbox.error_hint")
39
+ : t(`inbox.${boot.phase}`);
32
40
  return (_jsxs("div", { "data-cp-name": "InboxBootStatus", "data-phase": boot.phase, className: clsx("flex flex-col items-center gap-2 px-6 pb-4 pt-7 text-center transition-opacity duration-200", !boot.isStatusVisible && "opacity-0"), children: [_jsx("p", { role: "status", "aria-live": "polite", className: "sr-only", children: boot.isStatusVisible ? `${title}. ${detail}` : "" }), _jsx(TypingBubble, { isError: isError }), _jsx("p", { "aria-hidden": "true", className: "text-base font-semibold text-gray-900", children: title }), _jsx("p", { "aria-hidden": "true", className: "min-h-[1.5em] text-sm text-gray-500", children: detail }), isError ? (_jsx(Button, { type: "primary", className: "mt-2", onClick: () => window.location.reload(), children: t("retry") })) : (_jsx("div", { className: "mt-1 flex w-[168px] max-w-full gap-1", children: SEGMENTS.map((segment) => (_jsx(BootProgressBar, { className: "flex-1", mode: segmentMode(segment, boot), value: boot.syncProgress, label: t("sync_progress_label") }, segment))) })), boot.isSlow && !isError && (_jsx("p", { className: "mt-1.5 rounded-lg bg-warning-25 px-3 py-2 text-[13px] leading-normal text-warning-900", children: t("inbox.slow") }))] }));
33
41
  };
34
42
  export default InboxBootStatus;
@@ -1 +1 @@
1
- {"version":3,"file":"CreateGroupForm.d.ts","sourceRoot":"","sources":["../../../src/components/group/CreateGroupForm.tsx"],"names":[],"mappings":"AAiBA,UAAU,oBAAoB;IAC5B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAC/B;AAED,QAAA,MAAM,eAAe,GAAI,sBAA6B,oBAAoB,4CA4OzE,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"CreateGroupForm.d.ts","sourceRoot":"","sources":["../../../src/components/group/CreateGroupForm.tsx"],"names":[],"mappings":"AAiBA,UAAU,oBAAoB;IAC5B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAC/B;AAED,QAAA,MAAM,eAAe,GAAI,sBAA6B,oBAAoB,4CA6OzE,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -38,7 +38,8 @@ const CreateGroupForm = ({ onDone, footerEl = null }) => {
38
38
  URL.revokeObjectURL(avatarPreviewUrlRef.current);
39
39
  }
40
40
  }, []);
41
- const isGroupNameValid = groupName.trim().length > 0;
41
+ // CRM names the group automatically when the name is left empty.
42
+ const isGroupNameValid = isCrm || groupName.trim().length > 0;
42
43
  const canSubmit = isGroupNameValid &&
43
44
  selectedMembers.length > 0 &&
44
45
  !isSubmitting &&
@@ -1 +1 @@
1
- {"version":3,"file":"CreateGroupFormCrmView.d.ts","sourceRoot":"","sources":["../../../src/components/group/CreateGroupFormCrmView.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAI7E,UAAU,2BAA2B;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,cAAc,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC;IACxC,eAAe,EAAE,mBAAmB,EAAE,CAAC;IACvC,uBAAuB,EAAE,CAAC,OAAO,EAAE,mBAAmB,EAAE,KAAK,IAAI,CAAC;IAClE,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,wDAAwD;IACxD,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;CAC9B;AAED,mGAAmG;AACnG,QAAA,MAAM,sBAAsB,GAAI,OAAO,2BAA2B,4CAiGjE,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
1
+ {"version":3,"file":"CreateGroupFormCrmView.d.ts","sourceRoot":"","sources":["../../../src/components/group/CreateGroupFormCrmView.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAI7E,UAAU,2BAA2B;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,cAAc,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC;IACxC,eAAe,EAAE,mBAAmB,EAAE,CAAC;IACvC,uBAAuB,EAAE,CAAC,OAAO,EAAE,mBAAmB,EAAE,KAAK,IAAI,CAAC;IAClE,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,wDAAwD;IACxD,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;CAC9B;AAED,mGAAmG;AACnG,QAAA,MAAM,sBAAsB,GAAI,OAAO,2BAA2B,4CAgGjE,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
@@ -16,7 +16,7 @@ const CreateGroupFormCrmView = (props) => {
16
16
  ];
17
17
  return (_jsxs("div", { className: "flex flex-col gap-4", "data-cp-name": "CreateGroupForm", children: [_jsxs("div", { className: "flex items-end gap-4", children: [_jsx(Upload, { accept: "image/jpeg, image/png, image/jpg", showUploadList: false, beforeUpload: props.onAvatarSelect, children: _jsx("button", { type: "button", "aria-label": t("create_group.add_avatar"), title: t("create_group.add_avatar"), className: `flex h-16 w-16 shrink-0 items-center justify-center overflow-hidden rounded-full border border-dashed border-gray-200 bg-gray-5 text-gray-600 ${FOCUS_RING_CLASS}`, children: props.avatarPreviewUrl ? (
18
18
  // eslint-disable-next-line @next/next/no-img-element
19
- _jsx("img", { src: props.avatarPreviewUrl, alt: "", className: clsx("h-full w-full object-cover", props.isAvatarUploading && "opacity-50") })) : (_jsx(StrokeIcon, { name: "camera", size: 22 })) }) }), _jsxs("div", { className: "flex flex-1 flex-col gap-1.5", children: [_jsxs("label", { htmlFor: "create-group-name", className: "text-[13px] font-medium text-gray-900", children: [_jsx("span", { className: "text-danger-600", children: "* " }), t("create_group.name_label")] }), _jsx(Input, { id: "create-group-name", size: "large", value: props.groupName, onChange: (event) => props.onGroupNameChange(event.target.value), maxLength: props.maxNameLength, placeholder: t("create_group.name_placeholder") })] })] }), _jsxs("fieldset", { className: "m-0 flex flex-col gap-2 border-0 p-0", children: [_jsx("legend", { className: "mb-2 p-0 text-[13px] font-medium text-gray-900", children: t("create_group.privacy_label") }), _jsx("div", { className: "flex gap-3", children: options.map((option) => {
19
+ _jsx("img", { src: props.avatarPreviewUrl, alt: "", className: clsx("h-full w-full object-cover", props.isAvatarUploading && "opacity-50") })) : (_jsx(StrokeIcon, { name: "camera", size: 22 })) }) }), _jsxs("div", { className: "flex flex-1 flex-col gap-1.5", children: [_jsx("label", { htmlFor: "create-group-name", className: "text-[13px] font-medium text-gray-900", children: t("create_group.name_label") }), _jsx(Input, { id: "create-group-name", size: "large", value: props.groupName, onChange: (event) => props.onGroupNameChange(event.target.value), maxLength: props.maxNameLength, placeholder: t("create_group.name_placeholder") })] })] }), _jsxs("fieldset", { className: "m-0 flex flex-col gap-2 border-0 p-0", children: [_jsx("legend", { className: "mb-2 p-0 text-[13px] font-medium text-gray-900", children: t("create_group.privacy_label") }), _jsx("div", { className: "flex gap-3", children: options.map((option) => {
20
20
  const checked = props.isPublic === option.value;
21
21
  return (_jsxs("label", { className: clsx("flex flex-1 cursor-pointer items-start gap-2.5 rounded-xl border p-3 focus-within:outline focus-within:outline-2 focus-within:outline-primary-200", checked ? "border-primary-400 bg-primary-25 shadow-[0_0_0_1px_var(--dc-color-primary)]" : "border-gray-50 bg-white"), children: [_jsx("input", { type: "radio", name: "group-privacy", checked: checked, onChange: () => props.onPublicChange(option.value), className: "m-0 mt-0.5 h-4 w-4 shrink-0 accent-primary-400" }), _jsxs("span", { className: "flex flex-col gap-1", children: [_jsxs("span", { className: "flex items-center gap-1.5 text-sm font-semibold text-gray-900", children: [_jsx(StrokeIcon, { name: option.icon, size: 16 }), option.label] }), _jsx("span", { className: "text-[13px] leading-snug text-gray-600", children: option.hint })] })] }, String(option.value)));
22
22
  }) })] }), _jsxs("fieldset", { className: "m-0 flex flex-col gap-2 border-0 p-0", children: [_jsxs("legend", { className: "mb-2 p-0 text-[13px] font-medium text-gray-900", children: [t("create_group.members_label"), " ", _jsx("span", { className: "font-normal text-gray-600", children: t("create_group.members_owner_note") })] }), _jsx(GroupMemberPicker, { selectedMembers: props.selectedMembers, onChangeSelectedMembers: props.onChangeSelectedMembers })] }), props.footerEl &&
@@ -1 +1 @@
1
- {"version":3,"file":"GroupMemberPickerCrm.d.ts","sourceRoot":"","sources":["../../../src/components/group/GroupMemberPickerCrm.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAKlE,QAAA,MAAM,oBAAoB,GAAI,wDAI3B,sBAAsB,4CAqIxB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"GroupMemberPickerCrm.d.ts","sourceRoot":"","sources":["../../../src/components/group/GroupMemberPickerCrm.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAKlE,QAAA,MAAM,oBAAoB,GAAI,wDAI3B,sBAAsB,4CAgJxB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -43,6 +43,6 @@ const GroupMemberPickerCrm = ({ selectedMembers, onChangeSelectedMembers, groupI
43
43
  }), accounts.map((account) => {
44
44
  const isSelected = selectedIds.has(account.userID);
45
45
  return (_jsx("li", { children: _jsxs("label", { className: clsx(rowClass, "cursor-pointer focus-within:outline focus-within:outline-2 focus-within:outline-primary-200", isSelected ? "bg-primary-25" : "hover:bg-gray-10"), children: [_jsx("input", { type: "checkbox", checked: isSelected, onChange: () => toggle(account), className: "m-0 h-[18px] w-[18px] shrink-0 accent-primary-400" }), _jsx(PersonAvatar, { name: account.displayName, src: account.avatar, size: 32 }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [_jsx("span", { className: "truncate text-sm leading-[18px] text-gray-900", children: account.displayName }), _jsx("span", { className: "truncate text-xs leading-4 text-gray-600", children: account.username })] })] }) }, account.userID));
46
- }), isFetchingNextPage && (_jsx("li", { className: "flex justify-center py-3", children: _jsx(Spin, { size: "small" }) }))] })) })] }), _jsxs("div", { className: "flex min-w-0 flex-col gap-2 rounded-xl bg-gray-5 p-3", children: [_jsx("span", { className: "text-[13px] font-semibold text-gray-900", children: t("create_group.selected_title", { count: selectedMembers.length }) }), selectedMembers.length === 0 ? (_jsx("span", { className: "text-sm text-gray-600", children: t("create_group.no_member_selected") })) : (_jsx("ul", { className: "m-0 flex list-none flex-col gap-1 overflow-y-auto p-0", children: selectedMembers.map((member) => (_jsxs("li", { className: "flex items-center gap-2 rounded-lg bg-white py-1 pl-1.5 pr-1", children: [_jsx(PersonAvatar, { name: member.displayName, src: member.avatar, size: 24 }), _jsx("span", { className: "min-w-0 flex-1 truncate text-[13px] text-gray-900", children: member.displayName }), _jsx("button", { type: "button", "aria-label": t("create_group.remove_selected", { name: member.displayName }), title: t("create_group.remove_selected", { name: member.displayName }), onClick: () => toggle(member), className: `flex h-6 w-6 shrink-0 items-center justify-center rounded text-gray-600 hover:bg-gray-25 ${FOCUS_RING_CLASS}`, children: _jsx(StrokeIcon, { name: "x", size: 14 }) })] }, member.userID))) }))] })] }));
46
+ }), isFetchingNextPage && (_jsx("li", { className: "flex justify-center py-3", children: _jsx(Spin, { size: "small" }) }))] })) })] }), _jsxs("div", { className: "flex min-w-0 flex-col gap-2 rounded-xl bg-gray-5 p-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-[13px] font-semibold text-gray-900", children: t("create_group.selected_title", { count: selectedMembers.length }) }), selectedMembers.length > 0 && (_jsx("button", { type: "button", onClick: () => onChangeSelectedMembers([]), className: `shrink-0 rounded px-1 text-[13px] font-medium text-primary-400 hover:underline ${FOCUS_RING_CLASS}`, children: t("create_group.clear_all") }))] }), selectedMembers.length === 0 ? (_jsx("span", { className: "text-sm text-gray-600", children: t("create_group.no_member_selected") })) : (_jsx("ul", { className: "m-0 flex list-none flex-col gap-1 overflow-y-auto p-0", children: selectedMembers.map((member) => (_jsxs("li", { className: "flex items-center gap-2 rounded-lg bg-white py-1 pl-1.5 pr-1", children: [_jsx(PersonAvatar, { name: member.displayName, src: member.avatar, size: 24 }), _jsx("span", { className: "min-w-0 flex-1 truncate text-[13px] text-gray-900", children: member.displayName }), _jsx("button", { type: "button", "aria-label": t("create_group.remove_selected", { name: member.displayName }), title: t("create_group.remove_selected", { name: member.displayName }), onClick: () => toggle(member), className: `flex h-6 w-6 shrink-0 items-center justify-center rounded text-gray-600 hover:bg-gray-25 ${FOCUS_RING_CLASS}`, children: _jsx(StrokeIcon, { name: "x", size: 14 }) })] }, member.userID))) }))] })] }));
47
47
  };
48
48
  export default GroupMemberPickerCrm;
@@ -1 +1 @@
1
- {"version":3,"file":"FileCollection.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/FileCollection.tsx"],"names":[],"mappings":"AAaA,QAAA,MAAM,cAAc,+CAsFnB,CAAC;AAEF,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"FileCollection.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/FileCollection.tsx"],"names":[],"mappings":"AAcA,QAAA,MAAM,cAAc,+CAsFnB,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -5,6 +5,7 @@ import InfiniteScroll from "react-infinite-scroll-component";
5
5
  import { Empty, Spin } from "antd";
6
6
  import { useCallback } from "react";
7
7
  import dayjs from "dayjs";
8
+ import { LIBRARY_DATE_HEADER_FORMAT } from "../../constants/dateFormat";
8
9
  import useConversationStore from "../../store/conversation";
9
10
  import { useTranslation } from "react-i18next";
10
11
  import { documentIcon } from "../../assets/svg";
@@ -20,7 +21,7 @@ const FileCollection = () => {
20
21
  },
21
22
  });
22
23
  const renderItem = useCallback((date, items) => {
23
- return (_jsxs("div", { className: "px-3", children: [_jsx("span", { className: "text-sm font-medium text-gray-500", children: dayjs(date).format("DD MMMM, YYYY") }), _jsx("div", { className: "flex flex-col gap-1 mt-2", children: items.map((item) => {
24
+ return (_jsxs("div", { className: "px-3", children: [_jsx("span", { className: "text-sm font-medium text-gray-500", children: dayjs(date).format(LIBRARY_DATE_HEADER_FORMAT) }), _jsx("div", { className: "flex flex-col gap-1 mt-2", children: items.map((item) => {
24
25
  var _a, _b, _c;
25
26
  const fileContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
26
27
  return (_jsxs("div", { className: "relative flex flex-row items-center gap-2 align-center bg-gray-100 rounded-md p-2 cursor-pointer", onClick: () => downloadFileFromUrl((fileContent === null || fileContent === void 0 ? void 0 : fileContent.sourceUrl) || "", (fileContent === null || fileContent === void 0 ? void 0 : fileContent.fileName) || ""), children: [documentIcon, _jsxs("div", { className: "flex flex-col flex-1", children: [_jsx("span", { className: "text-sm font-medium", children: shortenFileName((fileContent === null || fileContent === void 0 ? void 0 : fileContent.fileName) || "", {
@@ -1 +1 @@
1
- {"version":3,"file":"ImageCollection.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/ImageCollection.tsx"],"names":[],"mappings":"AAaA,QAAA,MAAM,eAAe,+CA2FpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"ImageCollection.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/ImageCollection.tsx"],"names":[],"mappings":"AAcA,QAAA,MAAM,eAAe,+CA2FpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -5,6 +5,7 @@ import InfiniteScroll from "react-infinite-scroll-component";
5
5
  import { Empty, Image, Spin } from "antd";
6
6
  import { useCallback } from "react";
7
7
  import dayjs from "dayjs";
8
+ import { LIBRARY_DATE_HEADER_FORMAT } from "../../constants/dateFormat";
8
9
  import useConversationStore from "../../store/conversation";
9
10
  import { images } from "../../constants/images";
10
11
  import { useTranslation } from "react-i18next";
@@ -21,7 +22,7 @@ const ImageCollection = () => {
21
22
  },
22
23
  });
23
24
  const renderItem = useCallback((date, items) => {
24
- return (_jsxs("div", { className: "mb-2", children: [_jsx("span", { className: "text-sm font-medium text-gray-500 px-3", children: dayjs(date).format("DD MMMM, YYYY") }), _jsx("div", { className: "grid grid-cols-3 justify-start gap-px py-2", children: items.map((item) => {
25
+ return (_jsxs("div", { className: "mb-2", children: [_jsx("span", { className: "text-sm font-medium text-gray-500 px-3", children: dayjs(date).format(LIBRARY_DATE_HEADER_FORMAT) }), _jsx("div", { className: "grid grid-cols-3 justify-start gap-px py-2", children: items.map((item) => {
25
26
  var _a, _b, _c, _d;
26
27
  const imageContent = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}");
27
28
  const sourceUrl = ((_b = imageContent.sourcePicture) === null || _b === void 0 ? void 0 : _b.url) ||
@@ -1 +1 @@
1
- {"version":3,"file":"LinkCollection.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/LinkCollection.tsx"],"names":[],"mappings":"AA+DA,QAAA,MAAM,cAAc,GAAI,aAAa;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,4CA6H3D,CAAC;AAEF,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"LinkCollection.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/LinkCollection.tsx"],"names":[],"mappings":"AA0DA,QAAA,MAAM,cAAc,GAAI,aAAa;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,4CAgI3D,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -3,36 +3,24 @@ import { Dropdown, Empty, Spin } from "antd";
3
3
  import { useTranslation } from "react-i18next";
4
4
  import useConversationStore from "../../store/conversation";
5
5
  import { useSearchMessage } from "../../hooks/search/useSearchMessage";
6
- import { useCallback, useEffect, useState } from "react";
6
+ import { useCallback } from "react";
7
7
  import dayjs from "dayjs";
8
+ import { LIBRARY_DATE_HEADER_FORMAT } from "../../constants/dateFormat";
8
9
  import InfiniteScroll from "react-infinite-scroll-component";
9
10
  import { MessageType, SessionType } from "@droppii-org/wasm-client-sdk";
10
11
  import { Icon } from "../../components/icon";
11
12
  import { DChatSDK } from "../../constants/sdk";
12
13
  import { useChatContext } from "../../context/ChatContext";
13
14
  import { message as antdMessage } from "antd";
14
- const LinkPreview = ({ url }) => {
15
- const [title, setTitle] = useState("");
16
- const [isLoading, setIsLoading] = useState(true);
17
- useEffect(() => {
18
- if (!url)
19
- return;
20
- setIsLoading(true);
21
- fetch(`https://api.microlink.io?url=${encodeURIComponent(url)}`)
22
- .then((res) => res.json())
23
- .then((res) => {
24
- var _a;
25
- if ((_a = res === null || res === void 0 ? void 0 : res.data) === null || _a === void 0 ? void 0 : _a.title) {
26
- setTitle(res.data.title);
27
- }
28
- })
29
- .catch(() => {
30
- setTitle("");
31
- })
32
- .finally(() => {
33
- setIsLoading(false);
34
- });
35
- }, [url]);
15
+ import { useFetchUrlMetadata } from "../../hooks/common/useFetchUrlMetadata";
16
+ import { parseUrlMetadata } from "../../utils/common";
17
+ const LinkPreview = ({ url, messageMetadata, }) => {
18
+ // Title saved on the message wins; otherwise ask the in-house metadata
19
+ // endpoint instead of a third-party service.
20
+ const hasMessageTitle = Boolean(messageMetadata === null || messageMetadata === void 0 ? void 0 : messageMetadata.title);
21
+ const { data, isLoading: isFetching } = useFetchUrlMetadata(url, !hasMessageTitle);
22
+ const title = (messageMetadata === null || messageMetadata === void 0 ? void 0 : messageMetadata.title) || ((data === null || data === void 0 ? void 0 : data.isEmpty) ? "" : data === null || data === void 0 ? void 0 : data.title) || "";
23
+ const isLoading = !hasMessageTitle && isFetching;
36
24
  return (_jsxs("a", { href: url, target: "_blank", rel: "noopener noreferrer", "data-cp-name": "LinkPreview", className: "flex flex-col truncate text-[var(--dc-color-link)] cursor-pointer", title: title || url, children: [isLoading && (_jsx("span", { className: "font-medium truncate text-gray-900", children: url })), !isLoading &&
37
25
  (title ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "font-medium truncate text-gray-900", children: title }), _jsx("span", { className: "text-sm text-gray-500 truncate", children: url })] })) : (_jsx("span", { className: "font-medium truncate text-gray-900", children: url })))] }));
38
26
  };
@@ -67,7 +55,7 @@ const LinkCollection = ({ onClose }) => {
67
55
  },
68
56
  });
69
57
  const renderItem = useCallback((date, items) => {
70
- return (_jsxs("div", { className: "px-3", children: [_jsx("span", { className: "text-sm font-medium text-gray-500 px-3", children: dayjs(date).format("DD MMMM, YYYY") }), _jsx("div", { className: "flex flex-col gap-1 mt-2", children: items.map((item) => {
58
+ return (_jsxs("div", { className: "px-3", children: [_jsx("span", { className: "text-sm font-medium text-gray-500 px-3", children: dayjs(date).format(LIBRARY_DATE_HEADER_FORMAT) }), _jsx("div", { className: "flex flex-col gap-1 mt-2", children: items.map((item) => {
71
59
  var _a, _b, _c;
72
60
  const urls = ((_b = JSON.parse(((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content) || "{}")) === null || _b === void 0 ? void 0 : _b.urls) || [];
73
61
  const menuItems = [
@@ -78,8 +66,8 @@ const LinkCollection = ({ onClose }) => {
78
66
  },
79
67
  ];
80
68
  return (_jsx("div", { children: urls.map((url, index) => {
81
- var _a;
82
- return (_jsxs("div", { className: "bg-gray-100 flex gap-2 items-center p-2 mb-1", children: [_jsx("div", { className: "flex items-center justify-center shrink-0", children: _jsx(Icon, { icon: "link-b", size: 16 }) }), _jsx("div", { className: "flex-1 min-w-0", children: _jsx(LinkPreview, { url: url }) }), _jsx(Dropdown, { menu: { items: menuItems }, trigger: ["click"], placement: "bottomRight", children: _jsx("div", { className: "flex items-center justify-center shrink-0 cursor-pointer p-1 hover:bg-gray-200 rounded ml-2", onClick: (e) => e.stopPropagation(), children: _jsx(Icon, { icon: "more-horizontal-b", size: 16 }) }) })] }, `${(_a = item.chatLog) === null || _a === void 0 ? void 0 : _a.clientMsgID}-${index}`));
69
+ var _a, _b;
70
+ return (_jsxs("div", { className: "bg-gray-100 flex gap-2 items-center p-2 mb-1", children: [_jsx("div", { className: "flex items-center justify-center shrink-0", children: _jsx(Icon, { icon: "link-b", size: 16 }) }), _jsx("div", { className: "flex-1 min-w-0", children: _jsx(LinkPreview, { url: url, messageMetadata: index === 0 ? parseUrlMetadata((_a = item.chatLog) === null || _a === void 0 ? void 0 : _a.ex) : undefined }) }), _jsx(Dropdown, { menu: { items: menuItems }, trigger: ["click"], placement: "bottomRight", children: _jsx("div", { className: "flex items-center justify-center shrink-0 cursor-pointer p-1 hover:bg-gray-200 rounded ml-2", onClick: (e) => e.stopPropagation(), children: _jsx(Icon, { icon: "more-horizontal-b", size: 16 }) }) })] }, `${(_b = item.chatLog) === null || _b === void 0 ? void 0 : _b.clientMsgID}-${index}`));
83
71
  }) }, (_c = item.chatLog) === null || _c === void 0 ? void 0 : _c.clientMsgID));
84
72
  }) })] }, date));
85
73
  }, []);
@@ -1 +1 @@
1
- {"version":3,"file":"VideoCollection.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/VideoCollection.tsx"],"names":[],"mappings":"AAiBA,QAAA,MAAM,eAAe,+CAqGpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"VideoCollection.d.ts","sourceRoot":"","sources":["../../../src/components/media-collection/VideoCollection.tsx"],"names":[],"mappings":"AAkBA,QAAA,MAAM,eAAe,+CAqGpB,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -5,6 +5,7 @@ import InfiniteScroll from "react-infinite-scroll-component";
5
5
  import { Empty, Image, Spin } from "antd";
6
6
  import { useState } from "react";
7
7
  import dayjs from "dayjs";
8
+ import { LIBRARY_DATE_HEADER_FORMAT } from "../../constants/dateFormat";
8
9
  import useConversationStore from "../../store/conversation";
9
10
  import { useBoolean } from "ahooks";
10
11
  import { images } from "../../constants/images";
@@ -29,7 +30,7 @@ const VideoCollection = () => {
29
30
  setTrue();
30
31
  };
31
32
  const renderItem = (date, items) => {
32
- return (_jsxs("div", { className: "mb-2", children: [_jsx("span", { className: "text-sm font-medium text-gray-500 px-3", children: dayjs(date).format("DD MMMM, YYYY") }), _jsx("div", { className: "grid grid-cols-3 justify-start gap-px py-2", children: items.map((item) => {
33
+ return (_jsxs("div", { className: "mb-2", children: [_jsx("span", { className: "text-sm font-medium text-gray-500 px-3", children: dayjs(date).format(LIBRARY_DATE_HEADER_FORMAT) }), _jsx("div", { className: "grid grid-cols-3 justify-start gap-px py-2", children: items.map((item) => {
33
34
  var _a, _b, _c, _d;
34
35
  const videoContent = parseMessageContent((_a = item === null || item === void 0 ? void 0 : item.chatLog) === null || _a === void 0 ? void 0 : _a.content);
35
36
  const globalIndex = (_c = videoIndexByMsgId.get((_b = item.chatLog) === null || _b === void 0 ? void 0 : _b.clientMsgID)) !== null && _c !== void 0 ? _c : 0;
@@ -1 +1 @@
1
- {"version":3,"file":"ResourceScrollContainer.d.ts","sourceRoot":"","sources":["../../../src/components/media-resources/ResourceScrollContainer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAa,MAAM,OAAO,CAAC;AAI7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGlD,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,mBAAmB,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAQD,QAAA,MAAM,uBAAuB,GAAI,+GAU9B,4BAA4B,4CAoD9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
1
+ {"version":3,"file":"ResourceScrollContainer.d.ts","sourceRoot":"","sources":["../../../src/components/media-resources/ResourceScrollContainer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAA+B,MAAM,OAAO,CAAC;AAI/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAGlD,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,mBAAmB,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAQD,QAAA,MAAM,uBAAuB,GAAI,+GAU9B,4BAA4B,4CAmF9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useEffect } from "react";
3
+ import { useEffect, useRef, useState } from "react";
4
4
  import InfiniteScroll from "react-infinite-scroll-component";
5
5
  import { Button, Spin } from "antd";
6
6
  import { useTranslation } from "react-i18next";
@@ -14,6 +14,38 @@ const ResourceScrollContainer = ({ tabKey, itemCount, isLoading, isError, hasNex
14
14
  fetchNextPage();
15
15
  }
16
16
  }, [isEmptyWithMorePages, isFetchingNextPage, fetchNextPage]);
17
+ // A page that fits without scrolling never fires the scroll trigger, so
18
+ // keep loading until the content overflows or the pages run out.
19
+ // The panel is mounted inside a closed drawer (display:none, 0 height), so a
20
+ // hidden container must not trigger background fetching; the resize tick
21
+ // re-checks once the drawer becomes visible.
22
+ const scrollRef = useRef(null);
23
+ const [resizeTick, setResizeTick] = useState(0);
24
+ const hasContainer = !isLoading && !isError && itemCount > 0;
25
+ useEffect(() => {
26
+ const el = scrollRef.current;
27
+ if (!el || typeof ResizeObserver === "undefined")
28
+ return;
29
+ const observer = new ResizeObserver(() => setResizeTick((n) => n + 1));
30
+ observer.observe(el);
31
+ return () => observer.disconnect();
32
+ }, [hasContainer]);
33
+ useEffect(() => {
34
+ const el = scrollRef.current;
35
+ if (!el || !hasNextPage || isFetchingNextPage || isError)
36
+ return;
37
+ if (!el.isConnected || el.clientHeight === 0)
38
+ return;
39
+ if (el.scrollHeight <= el.clientHeight)
40
+ fetchNextPage();
41
+ }, [
42
+ itemCount,
43
+ hasNextPage,
44
+ isFetchingNextPage,
45
+ isError,
46
+ fetchNextPage,
47
+ resizeTick,
48
+ ]);
17
49
  if (isLoading || isEmptyWithMorePages) {
18
50
  return (_jsx("div", { className: "flex h-full items-center justify-center py-6", children: _jsx(Spin, {}) }));
19
51
  }
@@ -24,6 +56,6 @@ const ResourceScrollContainer = ({ tabKey, itemCount, isLoading, isError, hasNex
24
56
  return _jsx(ResourceEmptyState, { tabKey: tabKey });
25
57
  }
26
58
  const scrollableId = `resource-scroll-${tabKey}`;
27
- return (_jsx("div", { id: scrollableId, "data-cp-name": "ResourceScrollContainer", className: "h-full overflow-auto", children: _jsx(InfiniteScroll, { dataLength: itemCount, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx(LoadingIndicator, {}), scrollableTarget: scrollableId, children: children }) }));
59
+ return (_jsx("div", { ref: scrollRef, id: scrollableId, "data-cp-name": "ResourceScrollContainer", className: "h-full overflow-auto", children: _jsx(InfiniteScroll, { dataLength: itemCount, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx(LoadingIndicator, {}), scrollableTarget: scrollableId, children: children }) }));
28
60
  };
29
61
  export default ResourceScrollContainer;
@@ -1 +1 @@
1
- {"version":3,"file":"GroupMembersDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/message/GroupMembersDrawer.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA8B/C,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA6BD,QAAA,MAAM,kBAAkB,GAAI,wDAKzB,uBAAuB,4CAusBzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"GroupMembersDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/message/GroupMembersDrawer.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA8B/C,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA6BD,QAAA,MAAM,kBAAkB,GAAI,wDAKzB,uBAAuB,4CAwsBzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}