@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,62 @@
1
+ import { $generateHtmlFromNodes } from "@lexical/html";
2
+ import { $createParagraphNode, $getRoot, $getSelection, $isRangeSelection } from "lexical";
3
+ import { $isListNode, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND, } from "@lexical/list";
4
+ import { $isQuoteNode } from "@lexical/rich-text";
5
+ import { clearComposerHistoryAfterUpdate } from "./clearComposerHistory";
6
+ // Resets only when the composer still holds what was sent; text typed while the
7
+ // message was being built stays as the next draft.
8
+ export const resetEditorIfUnchanged = (editor, sent) => {
9
+ let plainText = "";
10
+ let richText = "";
11
+ editor.getEditorState().read(() => {
12
+ plainText = $getRoot().getTextContent();
13
+ richText = $generateHtmlFromNodes(editor);
14
+ });
15
+ if (plainText !== sent.plainText || richText !== sent.richText)
16
+ return;
17
+ resetEditorAfterSend(editor);
18
+ };
19
+ // Empties the composer after a send but keeps the typing format, list and quote
20
+ // context, so the next message continues in the same block style.
21
+ export const resetEditorAfterSend = (editor) => {
22
+ clearComposerHistoryAfterUpdate(editor);
23
+ editor.update(() => {
24
+ const root = $getRoot();
25
+ root.clear();
26
+ const paragraph = $createParagraphNode();
27
+ root.append(paragraph);
28
+ paragraph.select();
29
+ const selection = $getSelection();
30
+ if ($isRangeSelection(selection)) {
31
+ const anchorNode = selection.anchor.getNode();
32
+ const topLevelNode = anchorNode.getTopLevelElementOrThrow();
33
+ const isListNode = $isListNode(topLevelNode);
34
+ const isQuoteNode = $isQuoteNode(topLevelNode);
35
+ const listType = isListNode
36
+ ? topLevelNode.getListType()
37
+ : undefined;
38
+ if (selection.hasFormat("bold")) {
39
+ selection.formatText("bold");
40
+ }
41
+ if (selection.hasFormat("italic")) {
42
+ selection.formatText("italic");
43
+ }
44
+ if (selection.hasFormat("strikethrough")) {
45
+ selection.formatText("strikethrough");
46
+ }
47
+ if (isQuoteNode) {
48
+ // Nếu đang là QuoteNode → chuyển về Paragraph (bình thường)
49
+ const paragraph = $createParagraphNode();
50
+ // copy con của quote sang paragraph
51
+ const children = topLevelNode.getChildren();
52
+ children.forEach((child) => paragraph.append(child));
53
+ topLevelNode.replace(paragraph);
54
+ }
55
+ if (isListNode && listType) {
56
+ editor.dispatchCommand(listType === "number"
57
+ ? INSERT_ORDERED_LIST_COMMAND
58
+ : INSERT_UNORDERED_LIST_COMMAND, undefined);
59
+ }
60
+ }
61
+ });
62
+ };
@@ -14,7 +14,6 @@ export interface CrmMemberMenuHandlers {
14
14
  }
15
15
  interface BuildCrmMemberMenuParams {
16
16
  member: MemberDisplayItem;
17
- isRealGroup: boolean;
18
17
  permissions: GroupPermissions;
19
18
  actingIsOwner: boolean;
20
19
  /** Set when leaving is not allowed; shown under the item instead of failing on click. */
@@ -24,9 +23,10 @@ interface BuildCrmMemberMenuParams {
24
23
  }
25
24
  type MenuItems = NonNullable<MenuProps["items"]>;
26
25
  /**
27
- * CRM member menu: no always-disabled entries, a short reason under every
28
- * entry that is disabled for lack of rights, owner transfer and removal set apart.
26
+ * CRM member menu: actions the viewer has no right to are left out instead of
27
+ * shown disabled. Only leave keeps a reason, since it depends on live state.
28
+ * Empty result means the "..." button is hidden.
29
29
  */
30
- export declare const buildCrmMemberMenu: ({ member, isRealGroup, permissions, actingIsOwner, leaveBlockedReason, handlers, t, }: BuildCrmMemberMenuParams) => MenuItems;
30
+ export declare const buildCrmMemberMenu: ({ member, permissions, actingIsOwner, leaveBlockedReason, handlers, t, }: BuildCrmMemberMenuParams) => MenuItems;
31
31
  export {};
32
32
  //# sourceMappingURL=groupMemberMenuCrm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"groupMemberMenuCrm.d.ts","sourceRoot":"","sources":["../../../src/components/message/groupMemberMenuCrm.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;AAE5E,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAClD,SAAS,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC/C,aAAa,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,gBAAgB,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtD,aAAa,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,gBAAgB,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtD,WAAW,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,UAAU,wBAAwB;IAChC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,gBAAgB,CAAC;IAC9B,aAAa,EAAE,OAAO,CAAC;IACvB,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,qBAAqB,CAAC;IAChC,CAAC,EAAE,SAAS,CAAC;CACd;AAED,KAAK,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;AAWjD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,uFAQhC,wBAAwB,KAAG,SAsF7B,CAAC"}
1
+ {"version":3,"file":"groupMemberMenuCrm.d.ts","sourceRoot":"","sources":["../../../src/components/message/groupMemberMenuCrm.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC;AAE5E,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAClD,SAAS,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC/C,aAAa,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,gBAAgB,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtD,aAAa,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,gBAAgB,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtD,WAAW,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,UAAU,wBAAwB;IAChC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,WAAW,EAAE,gBAAgB,CAAC;IAC9B,aAAa,EAAE,OAAO,CAAC;IACvB,yFAAyF;IACzF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,qBAAqB,CAAC;IAChC,CAAC,EAAE,SAAS,CAAC;CACd;AAED,KAAK,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;AAWjD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,0EAOhC,wBAAwB,KAAG,SA4F7B,CAAC"}
@@ -3,11 +3,11 @@ import { CrmIcon as Icon } from "../../components/group/crmIcon";
3
3
  const label = (title, hint, tone) => (_jsxs("span", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: tone, children: title }), hint && _jsx("span", { className: "text-xs font-normal text-gray-600", children: hint })] }));
4
4
  const DIVIDER = { type: "divider" };
5
5
  /**
6
- * CRM member menu: no always-disabled entries, a short reason under every
7
- * entry that is disabled for lack of rights, owner transfer and removal set apart.
6
+ * CRM member menu: actions the viewer has no right to are left out instead of
7
+ * shown disabled. Only leave keeps a reason, since it depends on live state.
8
+ * Empty result means the "..." button is hidden.
8
9
  */
9
- export const buildCrmMemberMenu = ({ member, isRealGroup, permissions, actingIsOwner, leaveBlockedReason, handlers, t, }) => {
10
- const ownerOnly = actingIsOwner ? undefined : t("group_owner_only");
10
+ export const buildCrmMemberMenu = ({ member, permissions, actingIsOwner, leaveBlockedReason, handlers, t, }) => {
11
11
  if (member.isCurrentUser) {
12
12
  return [
13
13
  {
@@ -20,64 +20,77 @@ export const buildCrmMemberMenu = ({ member, isRealGroup, permissions, actingIsO
20
20
  },
21
21
  ];
22
22
  }
23
- const removeReason = !permissions.removeMember
24
- ? t("need_remove_member_permission")
25
- : member.isOwner
26
- ? t("cannot_remove_group_owner")
27
- : member.isAdmin && !actingIsOwner
28
- ? t("group_owner_only")
29
- : undefined;
23
+ // Mute and remove share one target guard: never the owner, and another admin only for the owner.
24
+ const canManageTarget = permissions.removeMember && !member.isOwner && (!member.isAdmin || actingIsOwner);
30
25
  const adminItems = member.isAdmin
31
26
  ? [
32
- {
33
- key: "configure-admin-permission",
34
- label: label(t("admin_permission_settings"), permissions.transferOwnership ? undefined : ownerOnly),
35
- icon: _jsx(Icon, { icon: "shield-o", size: 16 }),
36
- disabled: !permissions.transferOwnership,
37
- onClick: () => handlers.onConfigureAdmin(member),
38
- },
39
- {
40
- key: "remove-admin",
41
- label: label(t("remove_from_admin"), permissions.addAdmin ? undefined : ownerOnly),
42
- icon: _jsx(Icon, { icon: "shield-fail-o", size: 16 }),
43
- disabled: !permissions.addAdmin,
44
- onClick: () => handlers.onRemoveAdmin(member),
45
- },
27
+ ...(permissions.transferOwnership
28
+ ? [
29
+ {
30
+ key: "configure-admin-permission",
31
+ label: label(t("admin_permission_settings")),
32
+ icon: _jsx(Icon, { icon: "shield-o", size: 16 }),
33
+ onClick: () => handlers.onConfigureAdmin(member),
34
+ },
35
+ ]
36
+ : []),
37
+ ...(permissions.addAdmin
38
+ ? [
39
+ {
40
+ key: "remove-admin",
41
+ label: label(t("remove_from_admin")),
42
+ icon: _jsx(Icon, { icon: "shield-fail-o", size: 16 }),
43
+ onClick: () => handlers.onRemoveAdmin(member),
44
+ },
45
+ ]
46
+ : []),
46
47
  ]
47
- : [
48
- {
49
- key: "assign-admin",
50
- label: label(t("assign_as_admin"), permissions.addAdmin ? undefined : ownerOnly),
51
- icon: _jsx(Icon, { icon: "shield-o", size: 16 }),
52
- disabled: !permissions.addAdmin,
53
- onClick: () => handlers.onAskAssignAdmin(member),
54
- },
55
- ];
56
- return [
57
- {
58
- key: "mute",
59
- label: label(member.isSendMessageDisabled ? t("unmute_member") : t("mute_member"), permissions.removeMember ? undefined : t("need_remove_member_permission")),
60
- icon: _jsx(Icon, { icon: "bell-off-o", size: 16 }),
61
- disabled: !permissions.removeMember,
62
- onClick: () => member.isSendMessageDisabled ? handlers.onToggleMute(member) : handlers.onAskMute(member),
63
- },
64
- ...adminItems,
65
- DIVIDER,
66
- {
67
- key: "transfer-owner",
68
- label: label(t("transfer_owner"), permissions.transferOwnership ? t("transfer_owner_hint") : ownerOnly, permissions.transferOwnership ? "text-warning-800" : undefined),
69
- icon: _jsx(Icon, { icon: "key-o", size: 16, className: permissions.transferOwnership ? "text-warning-800" : undefined }),
70
- disabled: !permissions.transferOwnership,
71
- onClick: () => handlers.onAskTransfer(member),
72
- },
73
- DIVIDER,
74
- {
75
- key: "remove-member",
76
- label: label(t("remove_from_group"), removeReason),
77
- icon: _jsx(Icon, { icon: "user-x", size: 16 }),
78
- danger: true,
79
- disabled: Boolean(removeReason),
80
- onClick: () => handlers.onAskRemove(member),
81
- },
48
+ : permissions.addAdmin
49
+ ? [
50
+ {
51
+ key: "assign-admin",
52
+ label: label(t("assign_as_admin")),
53
+ icon: _jsx(Icon, { icon: "shield-o", size: 16 }),
54
+ onClick: () => handlers.onAskAssignAdmin(member),
55
+ },
56
+ ]
57
+ : [];
58
+ const groups = [
59
+ canManageTarget
60
+ ? [
61
+ {
62
+ key: "mute",
63
+ label: label(member.isSendMessageDisabled ? t("unmute_member") : t("mute_member")),
64
+ icon: _jsx(Icon, { icon: "bell-off-o", size: 16 }),
65
+ onClick: () => member.isSendMessageDisabled ? handlers.onToggleMute(member) : handlers.onAskMute(member),
66
+ },
67
+ ]
68
+ : [],
69
+ adminItems,
70
+ permissions.transferOwnership
71
+ ? [
72
+ {
73
+ key: "transfer-owner",
74
+ label: label(t("transfer_owner"), t("transfer_owner_hint"), "text-warning-800"),
75
+ icon: _jsx(Icon, { icon: "key-o", size: 16, className: "text-warning-800" }),
76
+ onClick: () => handlers.onAskTransfer(member),
77
+ },
78
+ ]
79
+ : [],
80
+ canManageTarget
81
+ ? [
82
+ {
83
+ key: "remove-member",
84
+ label: label(t("remove_from_group")),
85
+ icon: _jsx(Icon, { icon: "user-x", size: 16 }),
86
+ danger: true,
87
+ onClick: () => handlers.onAskRemove(member),
88
+ },
89
+ ]
90
+ : [],
82
91
  ];
92
+ // Dividers only between non-empty groups so the menu never starts, ends or doubles up on one.
93
+ return groups
94
+ .filter((group) => group.length > 0)
95
+ .flatMap((group, index) => (index === 0 ? group : [DIVIDER, ...group]));
83
96
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SystemLogMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/SystemLogMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAS3D,UAAU,yBAAyB;IACjC,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,QAAA,MAAM,oBAAoB,GAAI,aAAa,yBAAyB,mDA0CnE,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"SystemLogMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/SystemLogMessage.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAU3D,UAAU,yBAAyB;IACjC,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,QAAA,MAAM,oBAAoB,GAAI,aAAa,yBAAyB,mDA4CnE,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -2,12 +2,15 @@
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { getSystemLogMessageHtml, getSystemLogMessageText, } from "../../../utils/messageLog";
4
4
  import { sanitizeHtml } from "../../../utils/common";
5
+ import { useTranslation } from "react-i18next";
5
6
  import useAuthStore from "../../../store/auth";
6
7
  import CrmSystemLine from "./CrmSystemLine";
7
8
  const SystemLogMessageItem = ({ message }) => {
8
9
  const isCrm = useAuthStore((state) => state.isCrm);
9
- const html = getSystemLogMessageHtml(message);
10
- const text = getSystemLogMessageText(message);
10
+ const viewerId = useAuthStore((state) => state.userID);
11
+ const { t } = useTranslation();
12
+ const html = getSystemLogMessageHtml(message, viewerId, t);
13
+ const text = getSystemLogMessageText(message, viewerId, t);
11
14
  if (!html && !text) {
12
15
  return null;
13
16
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,IAAI,eAAe,EAG/B,MAAM,8BAA8B,CAAC;AA8DtC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAClD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,iBAAiB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;CAClC;AAiDD,QAAA,MAAM,WAAW,GAAI,kSAkBlB,gBAAgB,mDA0flB,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,IAAI,eAAe,EAG/B,MAAM,8BAA8B,CAAC;AA8DtC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAClD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,iBAAiB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,gEAAgE;IAChE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;CAClC;AAiDD,QAAA,MAAM,WAAW,GAAI,kSAkBlB,gBAAgB,mDA2flB,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -79,6 +79,7 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
79
79
  });
80
80
  }
81
81
  if (isDeliveredForUi &&
82
+ !(message === null || message === void 0 ? void 0 : message.isInternal) &&
82
83
  isPinnableMessageType(message === null || message === void 0 ? void 0 : message.contentType) &&
83
84
  onPinMessage &&
84
85
  onUnpinMessage) {
@@ -15,7 +15,7 @@ const SearchConversationAsGroups = (props) => {
15
15
  scope,
16
16
  });
17
17
  if ((groups.length === 0 && !isLoading) || searchTerm.trim() === "")
18
- return _jsx(Empty, { description: t("no_conversation") });
18
+ return _jsx(Empty, { description: t("search_no_result") });
19
19
  if (isLoading)
20
20
  return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
21
21
  return (_jsx("div", { id: "scrollableSearchGroupsTab", className: "h-full overflow-auto", "data-cp-name": "SearchConversationAsGroups", children: _jsx(InfiniteScroll, { dataLength: groups.length, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableSearchGroupsTab", children: groups.map((item) => (_jsx(SearchItemAsGroup, { group: item, searchTerm: searchTerm }, item.conversationId))) }) }));
@@ -18,7 +18,7 @@ const SearchConversationAsMessages = (props) => {
18
18
  options: { scope },
19
19
  });
20
20
  if ((dataFlatten.length === 0 && !isLoading) || searchTerm.trim() === "")
21
- return _jsx(Empty, { description: t("no_conversation") });
21
+ return _jsx(Empty, { description: t("search_no_result") });
22
22
  if (isLoading)
23
23
  return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
24
24
  return (_jsx("div", { id: "scrollableSearchMessagesTab", className: "h-full overflow-auto", "data-cp-name": "SearchConversationAsMessages", children: _jsx(InfiniteScroll, { dataLength: dataFlatten.length, next: fetchNextPage, hasMore: hasNextPage, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableSearchMessagesTab", children: dataFlatten.map((item) => (_jsx(SearchItemAsMessage, { message: item.chatLog, searchTerm: searchTerm, displayTag: item.displayTag, tag: item.tag }, item.chatLog.clientMsgID))) }) }));
@@ -16,7 +16,7 @@ const SearchConversationMyInbox = ({ searchTerm = "", }) => {
16
16
  options: { untilEmptyPage: true },
17
17
  });
18
18
  if ((dataFlatten.length === 0 && !isLoading) || searchTerm.trim() === "")
19
- return _jsx(Empty, { description: t("no_conversation") });
19
+ return _jsx(Empty, { description: t("search_no_result") });
20
20
  if (isLoading)
21
21
  return (_jsx("div", { className: "flex items-center justify-center", children: _jsx(Spin, {}) }));
22
22
  return (_jsxs("div", { className: "overflow-auto", "data-cp-name": "SearchConversationMyInbox", children: [dataFlatten.map((item) => (_jsx(SearchItemAsMessage, { message: item.chatLog, searchTerm: searchTerm, displayTag: item.displayTag }, item.chatLog.clientMsgID))), _jsx("div", { className: "flex justify-center py-2", children: _jsx(Button, { type: "link", loading: isFetchingNextPage, onClick: () => fetchNextPage(), children: t("see_more") }) })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"GroupInfoBodyCrm.d.ts","sourceRoot":"","sources":["../../../src/components/thread/GroupInfoBodyCrm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAUzC,MAAM,MAAM,YAAY,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,aAAa,CAAC;AACpF,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9D,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,sBAAsB,EAAE,OAAO,CAAC;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAClD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,KAAK,IAAI,CAAC;IACrD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,KAAK,IAAI,CAAC;IACtD,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,KAAK,IAAI,CAAC;IACpD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC/D,oBAAoB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,SAAS,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IACvC,SAAS,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAC/C;AA6BD,kGAAkG;AAClG,QAAA,MAAM,gBAAgB,GAAI,OAAO,qBAAqB,4CA4JrD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"GroupInfoBodyCrm.d.ts","sourceRoot":"","sources":["../../../src/components/thread/GroupInfoBodyCrm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAUzC,MAAM,MAAM,YAAY,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,aAAa,CAAC;AACpF,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9D,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,sBAAsB,EAAE,OAAO,CAAC;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAClD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,KAAK,IAAI,CAAC;IACrD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,KAAK,IAAI,CAAC;IACtD,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,KAAK,IAAI,CAAC;IACpD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC/D,oBAAoB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,SAAS,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IACvC,SAAS,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAC/C;AA6BD,kGAAkG;AAClG,QAAA,MAAM,gBAAgB,GAAI,OAAO,qBAAqB,4CAwJrD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -29,13 +29,13 @@ const GroupInfoBodyCrm = (props) => {
29
29
  const nameChanged = props.nameValue.trim() !== "" && props.nameValue.trim() !== ((_a = props.groupName) !== null && _a !== void 0 ? _a : "");
30
30
  const descChanged = props.descriptionValue.trim() !== ((_b = props.introduction) !== null && _b !== void 0 ? _b : "");
31
31
  const hasAdminRows = props.canConfigPermissions || props.showInviteLink;
32
- return (_jsxs("div", { className: "flex flex-1 flex-col gap-4 overflow-y-auto p-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("span", { className: "relative block h-[60px] w-[60px] shrink-0", children: [_jsx(GroupAvatar, { faceURL: props.faceURL, groupName: props.groupName, size: 56 }), props.isAvatarUploading && (_jsx("span", { className: "absolute left-0 top-0 flex h-14 w-14 items-center justify-center rounded-full bg-gray-900/30", children: _jsx("span", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }) })), props.canEditAvatar && (_jsxs(_Fragment, { children: [_jsx("input", { ref: props.avatarInputRef, type: "file", accept: ACCEPTED_IMAGE_TYPES.join(", "), className: "hidden", onChange: props.onAvatarSelect }), _jsx("button", { type: "button", disabled: props.isAvatarUploading, onClick: props.onAvatarClick, "aria-label": t("group_info_edit_avatar"), title: t("group_info_edit_avatar"), className: `absolute bottom-0 right-0 flex h-6 w-6 items-center justify-center rounded-full border-2 border-white bg-gray-900 text-white ${FOCUS_RING_CLASS}`, children: _jsx(Icon, { icon: "camera-o", size: 12 }) })] }))] }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [editingField === "name" ? (_jsx(Input, { autoFocus: true, value: props.nameValue, onChange: (event) => props.onNameChange(event.target.value), maxLength: 255, disabled: props.isSaving, "aria-label": t("group_info_edit_name"), onPressEnter: () => nameChanged && props.onSaveEdit("name") })) : (_jsxs("span", { className: "flex items-center gap-0.5", children: [_jsx("span", { className: "truncate text-base font-semibold text-gray-900", title: props.groupName, children: props.groupName }), props.canEditName && (_jsx("button", { type: "button", className: `h-7 w-7 ${ICON_BUTTON}`, onClick: () => props.onStartEdit("name"), "aria-label": t("group_info_edit_name"), title: t("group_info_edit_name"), children: _jsx(Icon, { icon: "edit-o", size: 16 }) }))] })), _jsxs("span", { className: "flex flex-wrap gap-1.5", children: [_jsx(Chip, { icon: props.isPublic ? "globe-o" : "lock-o", tone: "primary", children: t(props.isPublic ? "group_visibility_public" : "group_visibility_private") }), typeof props.memberCount === "number" && (_jsx(Chip, { icon: "user-two-o", tone: "neutral", children: t("member_count", { count: props.memberCount }) }))] })] })] }), editingField === "name" && (_jsx(EditActions, { disabled: props.isSaving, canSave: !props.isSaving && nameChanged, onCancel: () => props.onCancelEdit("name"), onSave: () => props.onSaveEdit("name") })), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("span", { className: "text-xs font-medium text-gray-600", children: t("description") }), editingField === "description" ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Input.TextArea, { ref: descriptionRef, value: props.descriptionValue, onChange: (event) => props.onDescriptionChange(event.target.value), placeholder: t("enter_group_description"), "aria-label": t("description"), autoSize: { minRows: 2, maxRows: 5 }, maxLength: 500, showCount: true, disabled: props.isSaving }), _jsx(EditActions, { disabled: props.isSaving, canSave: !props.isSaving && descChanged, onCancel: () => props.onCancelEdit("description"), onSave: () => props.onSaveEdit("description") })] })) : (_jsxs(_Fragment, { children: [_jsx("p", { className: "m-0 whitespace-pre-wrap break-words text-sm text-gray-600", children: hasDescription ? props.introduction : t("group_info_no_description") }), props.canEditDescription && (_jsxs("button", { type: "button", onClick: () => props.onStartEdit("description"), className: `flex h-6 items-center gap-1.5 self-start rounded-lg text-[13px] font-medium text-primary-500 hover:text-primary-600 ${FOCUS_RING_CLASS}`, children: [_jsx(Icon, { icon: hasDescription ? "edit-o" : "plus-o", size: 14 }), t(hasDescription ? "group_info_edit_description" : "group_info_add_description")] }))] }))] }), _jsx(SectionLabel, { children: t("group_settings_section") }), _jsx(InfoCard, { children: [
32
+ return (_jsxs("div", { className: "flex flex-1 flex-col gap-4 overflow-y-auto p-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("span", { className: "relative block h-[60px] w-[60px] shrink-0", children: [_jsx(GroupAvatar, { faceURL: props.faceURL, groupName: props.groupName, size: 56 }), props.isAvatarUploading && (_jsx("span", { className: "absolute left-0 top-0 flex h-14 w-14 items-center justify-center rounded-full bg-gray-900/30", children: _jsx("span", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }) })), props.canEditAvatar && (_jsxs(_Fragment, { children: [_jsx("input", { ref: props.avatarInputRef, type: "file", accept: ACCEPTED_IMAGE_TYPES.join(", "), className: "hidden", onChange: props.onAvatarSelect }), _jsx("button", { type: "button", disabled: props.isAvatarUploading, onClick: props.onAvatarClick, "aria-label": t("group_info_edit_avatar"), title: t("group_info_edit_avatar"), className: `absolute bottom-0 right-0 flex h-6 w-6 items-center justify-center rounded-full border-2 border-white bg-gray-900 text-white ${FOCUS_RING_CLASS}`, children: _jsx(Icon, { icon: "camera-o", size: 12 }) })] }))] }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [editingField === "name" ? (_jsx(Input, { autoFocus: true, value: props.nameValue, onChange: (event) => props.onNameChange(event.target.value), maxLength: 255, showCount: true, disabled: props.isSaving, "aria-label": t("group_info_edit_name"), onPressEnter: () => nameChanged && props.onSaveEdit("name") })) : (_jsxs("span", { className: "flex items-center gap-0.5", children: [_jsx("span", { className: "truncate text-base font-semibold text-gray-900", title: props.groupName, children: props.groupName }), props.canEditName && (_jsx("button", { type: "button", className: `h-7 w-7 ${ICON_BUTTON}`, onClick: () => props.onStartEdit("name"), "aria-label": t("group_info_edit_name"), title: t("group_info_edit_name"), children: _jsx(Icon, { icon: "edit-o", size: 16 }) }))] })), _jsxs("span", { className: "flex flex-wrap gap-1.5", children: [_jsx(Chip, { icon: props.isPublic ? "globe-o" : "lock-o", tone: "primary", children: t(props.isPublic ? "group_visibility_public" : "group_visibility_private") }), typeof props.memberCount === "number" && (_jsx(Chip, { icon: "user-two-o", tone: "neutral", children: t("member_count", { count: props.memberCount }) }))] })] })] }), editingField === "name" && (_jsx(EditActions, { disabled: props.isSaving, canSave: !props.isSaving && nameChanged, onCancel: () => props.onCancelEdit("name"), onSave: () => props.onSaveEdit("name") })), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("span", { className: "text-xs font-medium text-gray-600", children: t("description") }), editingField === "description" ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Input.TextArea, { ref: descriptionRef, value: props.descriptionValue, onChange: (event) => props.onDescriptionChange(event.target.value), placeholder: t("enter_group_description"), "aria-label": t("description"), autoSize: { minRows: 2, maxRows: 5 }, maxLength: 500, showCount: true, disabled: props.isSaving }), _jsx(EditActions, { disabled: props.isSaving, canSave: !props.isSaving && descChanged, onCancel: () => props.onCancelEdit("description"), onSave: () => props.onSaveEdit("description") })] })) : (_jsxs(_Fragment, { children: [_jsx("p", { className: "m-0 whitespace-pre-wrap break-words text-sm text-gray-600", children: hasDescription ? props.introduction : t("group_info_no_description") }), props.canEditDescription && (_jsxs("button", { type: "button", onClick: () => props.onStartEdit("description"), className: `flex h-6 items-center gap-1.5 self-start rounded-lg text-[13px] font-medium text-primary-500 hover:text-primary-600 ${FOCUS_RING_CLASS}`, children: [_jsx(Icon, { icon: hasDescription ? "edit-o" : "plus-o", size: 14 }), t(hasDescription ? "group_info_edit_description" : "group_info_add_description")] }))] }))] }), _jsx(SectionLabel, { children: t("group_settings_section") }), _jsx(InfoCard, { children: [
33
33
  _jsx(SwitchRow, { icon: "bell-o", label: t("notification"), checked: props.notifyEnabled, loading: props.isTogglingNotification, onChange: props.onToggleNotification }, "notify"),
34
34
  props.showAllowSend && (_jsx(SwitchRow, { icon: "chat-square-o", label: t("members_can_send_message"), hint: t("allow_send_message_hint"), checked: props.allowSendMessage, loading: props.isTogglingSendMessage, onChange: props.onToggleSendMessage }, "send")),
35
35
  ] }), hasAdminRows && (_jsxs(_Fragment, { children: [_jsx(SectionLabel, { children: t("group_admin_section") }), _jsx(InfoCard, { children: [
36
36
  props.canConfigPermissions && _jsx(NavRow, { icon: "shield-o", label: t("member_permission_row"), onClick: () => props.onOpenRow("member-permission") }, "member"),
37
37
  props.canConfigPermissions && _jsx(NavRow, { icon: "shield-o", label: t("admin_permission_row"), onClick: () => props.onOpenRow("admin-permission") }, "admin"),
38
38
  props.showInviteLink && _jsx(NavRow, { icon: "link-alt-o", label: t("invite_via_link_short"), onClick: () => props.onOpenRow("invite-link") }, "invite"),
39
- ] })] })), _jsxs("div", { className: "flex flex-col gap-0.5 border-t border-gray-25 pt-2", children: [props.isAdminOrOwner && _jsx(DangerRow, { icon: "trash-o", label: t("group_delete_conversation"), onClick: () => props.onConfirm("delete") }), !props.isViewOnlyMember && _jsx(DangerRow, { icon: "logout-o", label: t("leave_group"), onClick: () => props.onConfirm("leave") }), !props.isViewOnlyMember && (_jsx(DangerRow, { icon: "user-del-o", label: t("disband_group"), onClick: () => props.onConfirm("disband"), disabledNote: props.isOwner ? undefined : t("group_owner_only") }))] })] }));
39
+ ] })] })), _jsxs("div", { className: "flex flex-col gap-0.5 border-t border-gray-25 pt-2", children: [props.isAdminOrOwner && _jsx(DangerRow, { icon: "trash-o", label: t("group_delete_conversation"), onClick: () => props.onConfirm("delete") }), !props.isViewOnlyMember && _jsx(DangerRow, { icon: "logout-o", label: t("leave_group"), onClick: () => props.onConfirm("leave") }), props.isOwner && (_jsx(DangerRow, { icon: "user-del-o", label: t("disband_group"), onClick: () => props.onConfirm("disband") }))] })] }));
40
40
  };
41
41
  export default GroupInfoBodyCrm;
@@ -1 +1 @@
1
- {"version":3,"file":"GroupThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/GroupThreadInfo.tsx"],"names":[],"mappings":"AA0BA,MAAM,WAAW,qBAAqB;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,UAAU,oBAAoB;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC;AASD,QAAA,MAAM,eAAe,GAAI,qBAAqB,oBAAoB,mDAirBjE,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"GroupThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/GroupThreadInfo.tsx"],"names":[],"mappings":"AA0BA,MAAM,WAAW,qBAAqB;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,UAAU,oBAAoB;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC;AASD,QAAA,MAAM,eAAe,GAAI,qBAAqB,oBAAoB,mDA6qBjE,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -47,10 +47,6 @@ const GroupThreadInfo = ({ onClose, config }) => {
47
47
  // Non-member viewing an existing public group in view-only mode — no
48
48
  // longer a member, so "Rời khỏi nhóm" (leave) doesn't apply.
49
49
  const isViewOnlyMember = useConversationStore((state) => state.isViewOnlyMember);
50
- // Feature ships to staging first (DROPPII-30551). Same env var apps/web already
51
- // reads in src/app/layout.tsx:51 — this repo has no feature-flag service and
52
- // this ticket is not the place to introduce one.
53
- const isInviteLinkFeatureEnabled = process.env.NEXT_PUBLIC_ENV === "stg";
54
50
  const [editingField, setEditingField] = useState(null);
55
51
  const [nameValue, setNameValue] = useState((_a = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName) !== null && _a !== void 0 ? _a : "");
56
52
  const [descriptionValue, setDescriptionValue] = useState((_b = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) !== null && _b !== void 0 ? _b : "");
@@ -256,10 +252,10 @@ const GroupThreadInfo = ({ onClose, config }) => {
256
252
  if (!groupID) {
257
253
  return null;
258
254
  }
259
- return (_jsxs("div", { className: "h-full w-full bg-white flex flex-col relative overflow-hidden", "data-cp-name": "GroupThreadInfo", children: [isCrm ? (_jsxs(_Fragment, { children: [_jsx(GroupPanelHeader, { title: t("group_info_title"), onClose: onClose }), _jsx(GroupInfoBodyCrm, { groupName: groupDisplayName, faceURL: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.faceURL, introduction: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction, memberCount: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.memberCount, isPublic: (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.visibility) === GroupVisibility.Public, canEditAvatar: permissions.updateGroupAvatar, canEditName: permissions.updateGroupName, canEditDescription: permissions.updateGroupDescription, canConfigPermissions: permissions.configGroupPermission, showInviteLink: isInviteLinkFeatureEnabled && !isViewOnlyMember, showAllowSend: Boolean(config === null || config === void 0 ? void 0 : config.showAllowSendMessage) && isOwner, isOwner: isOwner, isAdminOrOwner: isAdminOrOwner, isViewOnlyMember: isViewOnlyMember, notifyEnabled: notifyEnabled, isTogglingNotification: isTogglingNotification, allowSendMessage: allowSendMessage, isTogglingSendMessage: isTogglingSendMessage, isAvatarUploading: isAvatarUploading, isSaving: isSavingGroupInfo, editingField: editingField, nameValue: nameValue, descriptionValue: descriptionValue, avatarInputRef: avatarInputRef, onNameChange: setNameValue, onDescriptionChange: setDescriptionValue, onStartEdit: (field) => (field === "name" ? startEditName() : startEditDescription()), onCancelEdit: (field) => (field === "name" ? cancelEditName() : cancelEditDescription()), onSaveEdit: (field) => (field === "name" ? saveName() : saveDescription()), onAvatarClick: handleAvatarClick, onAvatarSelect: handleAvatarSelect, onToggleNotification: handleToggleNotification, onToggleSendMessage: handleToggleSendMessage, onOpenRow: setActiveRow, onConfirm: setConfirmAction })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-4 border-b border-gray-100", children: [_jsx("span", { className: "text-lg font-medium", children: t("thread_info_title") }), _jsx("button", { type: "button", className: "flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:bg-gray-100", onClick: onClose, children: _jsx(Icon, { icon: "close-o", size: 20 }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-4", children: [_jsxs("div", { className: "relative shrink-0", children: [_jsx(GroupAvatar, { faceURL: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.faceURL, groupName: groupDisplayName, size: 56 }), isAvatarUploading && (_jsx("span", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-black/30", children: _jsx("span", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }) })), permissions.updateGroupAvatar && (_jsxs(_Fragment, { children: [_jsx("input", { ref: avatarInputRef, type: "file", accept: ACCEPTED_IMAGE_TYPES.join(", "), className: "hidden", onChange: handleAvatarSelect }), _jsx("button", { type: "button", disabled: isAvatarUploading, onClick: handleAvatarClick, className: "absolute -bottom-1 -right-1 flex items-center justify-center w-5 h-5 rounded-full bg-black text-white", children: _jsx(Icon, { icon: "camera-o", size: 12 }) })] }))] }), _jsx("div", { className: "flex-1 min-w-0", children: editingField !== "name" && (_jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("p", { className: "text-base font-medium truncate", children: groupDisplayName }), permissions.updateGroupName && (_jsx(Icon, { icon: "edit-o", size: 16, className: "shrink-0 cursor-pointer text-gray-500", onClick: startEditName }))] })) })] }), editingField === "name" && (_jsx("div", { className: "px-4 pb-4", children: _jsxs("div", { className: "flex flex-col gap-3 bg-[#f5f5f5] rounded-lg p-3", children: [_jsx(Input, { autoFocus: true, value: nameValue, onChange: (event) => setNameValue(event.target.value), maxLength: 255, showCount: true, disabled: isSavingGroupInfo, className: "bg-white" }), _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx("button", { type: "button", className: "px-4 py-1.5 rounded-lg border border-[var(--dc-color-primary-hover)] text-[var(--dc-color-primary-hover)] text-sm font-medium disabled:border-gray-200 disabled:text-gray-300", disabled: isSavingGroupInfo, onClick: cancelEditName, children: t("cancel") }), _jsx("button", { type: "button", className: "px-4 py-1.5 rounded-lg bg-[var(--dc-color-primary-hover)] text-white text-sm font-medium disabled:bg-gray-100 disabled:text-gray-300", disabled: isSavingGroupInfo ||
255
+ return (_jsxs("div", { className: "h-full w-full bg-white flex flex-col relative overflow-hidden", "data-cp-name": "GroupThreadInfo", children: [isCrm ? (_jsxs(_Fragment, { children: [_jsx(GroupPanelHeader, { title: t("group_info_title"), onClose: onClose }), _jsx(GroupInfoBodyCrm, { groupName: groupDisplayName, faceURL: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.faceURL, introduction: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction, memberCount: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.memberCount, isPublic: (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.visibility) === GroupVisibility.Public, canEditAvatar: permissions.updateGroupAvatar, canEditName: permissions.updateGroupName, canEditDescription: permissions.updateGroupDescription, canConfigPermissions: permissions.configGroupPermission, showInviteLink: !isViewOnlyMember, showAllowSend: Boolean(config === null || config === void 0 ? void 0 : config.showAllowSendMessage) && isOwner, isOwner: isOwner, isAdminOrOwner: isAdminOrOwner, isViewOnlyMember: isViewOnlyMember, notifyEnabled: notifyEnabled, isTogglingNotification: isTogglingNotification, allowSendMessage: allowSendMessage, isTogglingSendMessage: isTogglingSendMessage, isAvatarUploading: isAvatarUploading, isSaving: isSavingGroupInfo, editingField: editingField, nameValue: nameValue, descriptionValue: descriptionValue, avatarInputRef: avatarInputRef, onNameChange: setNameValue, onDescriptionChange: setDescriptionValue, onStartEdit: (field) => (field === "name" ? startEditName() : startEditDescription()), onCancelEdit: (field) => (field === "name" ? cancelEditName() : cancelEditDescription()), onSaveEdit: (field) => (field === "name" ? saveName() : saveDescription()), onAvatarClick: handleAvatarClick, onAvatarSelect: handleAvatarSelect, onToggleNotification: handleToggleNotification, onToggleSendMessage: handleToggleSendMessage, onOpenRow: setActiveRow, onConfirm: setConfirmAction })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-4 border-b border-gray-100", children: [_jsx("span", { className: "text-lg font-medium", children: t("thread_info_title") }), _jsx("button", { type: "button", className: "flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:bg-gray-100", onClick: onClose, children: _jsx(Icon, { icon: "close-o", size: 20 }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-4", children: [_jsxs("div", { className: "relative shrink-0", children: [_jsx(GroupAvatar, { faceURL: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.faceURL, groupName: groupDisplayName, size: 56 }), isAvatarUploading && (_jsx("span", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-black/30", children: _jsx("span", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }) })), permissions.updateGroupAvatar && (_jsxs(_Fragment, { children: [_jsx("input", { ref: avatarInputRef, type: "file", accept: ACCEPTED_IMAGE_TYPES.join(", "), className: "hidden", onChange: handleAvatarSelect }), _jsx("button", { type: "button", disabled: isAvatarUploading, onClick: handleAvatarClick, className: "absolute -bottom-1 -right-1 flex items-center justify-center w-5 h-5 rounded-full bg-black text-white", children: _jsx(Icon, { icon: "camera-o", size: 12 }) })] }))] }), _jsx("div", { className: "flex-1 min-w-0", children: editingField !== "name" && (_jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("p", { className: "text-base font-medium truncate", children: groupDisplayName }), permissions.updateGroupName && (_jsx(Icon, { icon: "edit-o", size: 16, className: "shrink-0 cursor-pointer text-gray-500", onClick: startEditName }))] })) })] }), editingField === "name" && (_jsx("div", { className: "px-4 pb-4", children: _jsxs("div", { className: "flex flex-col gap-3 bg-[#f5f5f5] rounded-lg p-3", children: [_jsx(Input, { autoFocus: true, value: nameValue, onChange: (event) => setNameValue(event.target.value), maxLength: 255, showCount: true, disabled: isSavingGroupInfo, className: "bg-white" }), _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx("button", { type: "button", className: "px-4 py-1.5 rounded-lg border border-[var(--dc-color-primary-hover)] text-[var(--dc-color-primary-hover)] text-sm font-medium disabled:border-gray-200 disabled:text-gray-300", disabled: isSavingGroupInfo, onClick: cancelEditName, children: t("cancel") }), _jsx("button", { type: "button", className: "px-4 py-1.5 rounded-lg bg-[var(--dc-color-primary-hover)] text-white text-sm font-medium disabled:bg-gray-100 disabled:text-gray-300", disabled: isSavingGroupInfo ||
260
256
  !nameValue.trim() ||
261
257
  nameValue.trim() === ((_c = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName) !== null && _c !== void 0 ? _c : ""), onClick: saveName, children: t("save") })] })] }) })), _jsx("div", { className: "px-4 pb-4", children: editingField === "description" ? (_jsxs("div", { className: "flex flex-col gap-3 bg-[#f5f5f5] rounded-lg p-3", children: [_jsxs("span", { className: "flex items-center gap-2 text-sm font-medium text-gray-900", children: [_jsx(Icon, { icon: "info-circle-o", size: 18, className: "text-gray-500" }), t("description")] }), _jsx(Input.TextArea, { ref: descriptionInputRef, value: descriptionValue, onChange: (event) => setDescriptionValue(event.target.value), placeholder: t("enter_group_description"), autoSize: { minRows: 1, maxRows: 4 }, maxLength: 500, disabled: isSavingGroupInfo, className: "bg-white" }), _jsxs("span", { className: "self-end text-xs text-gray-400", children: [descriptionValue.length, " / 500"] }), _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx("button", { type: "button", className: "px-4 py-1.5 rounded-lg border border-[var(--dc-color-primary-hover)] text-[var(--dc-color-primary-hover)] text-sm font-medium disabled:border-gray-200 disabled:text-gray-300", disabled: isSavingGroupInfo, onClick: cancelEditDescription, children: t("cancel") }), _jsx("button", { type: "button", className: "px-4 py-1.5 rounded-lg bg-[var(--dc-color-primary-hover)] text-white text-sm font-medium disabled:bg-gray-100 disabled:text-gray-300", disabled: isSavingGroupInfo ||
262
- descriptionValue.trim() === ((_d = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) !== null && _d !== void 0 ? _d : ""), onClick: saveDescription, children: t("save") })] })] })) : (_jsxs("div", { className: "flex items-start justify-between gap-2 bg-[#f5f5f5] rounded-lg px-3 py-2.5", children: [_jsxs("div", { className: "flex items-start gap-2 flex-1 min-w-0", children: [_jsx(Icon, { icon: "info-circle-o", size: 18, className: "shrink-0 mt-0.5 text-gray-900" }), _jsxs("div", { className: "flex flex-col gap-0.5 min-w-0", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: t("description") }), _jsx("p", { className: "text-sm text-gray-400 truncate", children: (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) || t("no_description") })] })] }), permissions.updateGroupDescription && (_jsx(Icon, { icon: "edit-o", size: 16, className: "shrink-0 cursor-pointer text-gray-500", onClick: startEditDescription }))] })) }), _jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 rounded-lg overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-o", size: 18 }), t("notification")] }), _jsx(Switch, { checked: notifyEnabled, onChange: handleToggleNotification, loading: isTogglingNotification })] }), (config === null || config === void 0 ? void 0 : config.showAllowSendMessage) && isOwner && (_jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "user-check-o", size: 18 }), t("allow_send_message")] }), _jsx(Switch, { checked: allowSendMessage, onChange: handleToggleSendMessage, loading: isTogglingSendMessage })] })), isAdminOrOwner && (config === null || config === void 0 ? void 0 : config.showMutedChatList) && (_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("muted-chat-list"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-off-o", size: 18 }), t("muted_chat_list")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })), isAdminOrOwner && (_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("block-list"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t("block_list")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] }))] }), permissions.configGroupPermission && (_jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: [_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("member-permission"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "shield-o", size: 18 }), t("member_permission_settings")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] }), _jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("admin-permission"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "shield-done-o", size: 18 }), t("admin_permission_settings")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })] })), isInviteLinkFeatureEnabled && !isViewOnlyMember && (_jsx("div", { className: "mx-4 mt-3 rounded-lg overflow-hidden bg-[#f5f5f5]", children: _jsxs("button", { type: "button", className: "w-full flex items-center justify-between px-3 py-3 text-left text-sm", onClick: () => setActiveRow("invite-link"), children: [_jsxs("span", { className: "flex items-center gap-3", children: [_jsx(Icon, { icon: "link-alt-o", size: 18 }), t("invite_via_link")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] }) })), _jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 mb-4 rounded-lg overflow-hidden", children: [isAdminOrOwner && (_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("delete"), children: [_jsx(Icon, { icon: "trash-o", size: 18 }), t("delete_conversation")] })), !isViewOnlyMember && (_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("leave"), children: [_jsx(Icon, { icon: "logout-o", size: 18 }), t("leave_group")] })), isOwner && (_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("disband"), children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t("disband_group")] }))] })] })] })), _jsx(ConfirmModal, { open: confirmAction === "leave", onOk: handleConfirmLeave, onCancel: () => setConfirmAction(null), title: t("leave_group_confirm_title"), okText: t("leave_group"), cancelText: t(isCrm ? "action_cancel" : "cancel"), okType: "danger", confirmLoading: isLeaving, children: _jsx("p", { children: t("leave_group_confirm_message") }) }), _jsx(ConfirmModal, { open: confirmAction === "disband", onOk: handleConfirmDisband, onCancel: () => setConfirmAction(null), title: t("disband_group_confirm_title"), okText: t("disband_group"), cancelText: t(isCrm ? "action_cancel" : "cancel"), okType: "danger", confirmLoading: isDismissing, children: _jsx("p", { children: t("disband_group_confirm_message") }) }), _jsx(ConfirmModal, { open: confirmAction === "delete", onOk: handleConfirmDelete, onCancel: () => setConfirmAction(null), title: t("delete_conversation_confirm_title"), okText: t("delete_conversation"), cancelText: t(isCrm ? "action_cancel" : "cancel"), okType: "danger", confirmLoading: isDeleting, children: _jsx("p", { children: t("delete_conversation_confirm_message") }) }), _jsx(DisableSendPermissionConfirm, { open: confirmAction === "mute-all", title: t("disable_send_permission_title_all_members"), onConfirm: () => {
258
+ descriptionValue.trim() === ((_d = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) !== null && _d !== void 0 ? _d : ""), onClick: saveDescription, children: t("save") })] })] })) : (_jsxs("div", { className: "flex items-start justify-between gap-2 bg-[#f5f5f5] rounded-lg px-3 py-2.5", children: [_jsxs("div", { className: "flex items-start gap-2 flex-1 min-w-0", children: [_jsx(Icon, { icon: "info-circle-o", size: 18, className: "shrink-0 mt-0.5 text-gray-900" }), _jsxs("div", { className: "flex flex-col gap-0.5 min-w-0", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: t("description") }), _jsx("p", { className: "text-sm text-gray-400 truncate", children: (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) || t("no_description") })] })] }), permissions.updateGroupDescription && (_jsx(Icon, { icon: "edit-o", size: 16, className: "shrink-0 cursor-pointer text-gray-500", onClick: startEditDescription }))] })) }), _jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 rounded-lg overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-o", size: 18 }), t("notification")] }), _jsx(Switch, { checked: notifyEnabled, onChange: handleToggleNotification, loading: isTogglingNotification })] }), (config === null || config === void 0 ? void 0 : config.showAllowSendMessage) && isOwner && (_jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "user-check-o", size: 18 }), t("allow_send_message")] }), _jsx(Switch, { checked: allowSendMessage, onChange: handleToggleSendMessage, loading: isTogglingSendMessage })] })), isAdminOrOwner && (config === null || config === void 0 ? void 0 : config.showMutedChatList) && (_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("muted-chat-list"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-off-o", size: 18 }), t("muted_chat_list")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })), isAdminOrOwner && (_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("block-list"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t("block_list")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] }))] }), permissions.configGroupPermission && (_jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: [_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("member-permission"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "shield-o", size: 18 }), t("member_permission_settings")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] }), _jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("admin-permission"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "shield-done-o", size: 18 }), t("admin_permission_settings")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })] })), !isViewOnlyMember && (_jsx("div", { className: "mx-4 mt-3 rounded-lg overflow-hidden bg-[#f5f5f5]", children: _jsxs("button", { type: "button", className: "w-full flex items-center justify-between px-3 py-3 text-left text-sm", onClick: () => setActiveRow("invite-link"), children: [_jsxs("span", { className: "flex items-center gap-3", children: [_jsx(Icon, { icon: "link-alt-o", size: 18 }), t("invite_via_link")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] }) })), _jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 mb-4 rounded-lg overflow-hidden", children: [isAdminOrOwner && (_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("delete"), children: [_jsx(Icon, { icon: "trash-o", size: 18 }), t("delete_conversation")] })), !isViewOnlyMember && (_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("leave"), children: [_jsx(Icon, { icon: "logout-o", size: 18 }), t("leave_group")] })), isOwner && (_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("disband"), children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t("disband_group")] }))] })] })] })), _jsx(ConfirmModal, { open: confirmAction === "leave", onOk: handleConfirmLeave, onCancel: () => setConfirmAction(null), title: t("leave_group_confirm_title"), okText: t("leave_group"), cancelText: t(isCrm ? "action_cancel" : "cancel"), okType: "danger", confirmLoading: isLeaving, children: _jsx("p", { children: t("leave_group_confirm_message") }) }), _jsx(ConfirmModal, { open: confirmAction === "disband", onOk: handleConfirmDisband, onCancel: () => setConfirmAction(null), title: t("disband_group_confirm_title"), okText: t("disband_group"), cancelText: t(isCrm ? "action_cancel" : "cancel"), okType: "danger", confirmLoading: isDismissing, children: _jsx("p", { children: t("disband_group_confirm_message") }) }), _jsx(ConfirmModal, { open: confirmAction === "delete", onOk: handleConfirmDelete, onCancel: () => setConfirmAction(null), title: t("delete_conversation_confirm_title"), okText: t("delete_conversation"), cancelText: t(isCrm ? "action_cancel" : "cancel"), okType: "danger", confirmLoading: isDeleting, children: _jsx("p", { children: t("delete_conversation_confirm_message") }) }), _jsx(DisableSendPermissionConfirm, { open: confirmAction === "mute-all", title: t("disable_send_permission_title_all_members"), onConfirm: () => {
263
259
  setConfirmAction(null);
264
260
  applySendMessage(false);
265
261
  }, onCancel: () => setConfirmAction(null) }), _jsx(MemberPermissionPanel, { open: activeRow === "member-permission", groupID: groupID, onClose: () => setActiveRow(null) }), _jsx(AdminPermissionModal, { open: activeRow === "admin-permission", groupID: groupID, onClose: () => setActiveRow(null), inline: true }), _jsx(InviteLinkPanel, { open: activeRow === "invite-link", groupID: groupID, conversationID: conversationID, onClose: () => setActiveRow(null) }), (activeRow === "muted-chat-list" || activeRow === "block-list") && (_jsx(Modal, { centered: true, open: true, footer: null, onCancel: () => setActiveRow(null), title: t(activeRow === "muted-chat-list" ? "muted_chat_list" : "block_list"), getContainer: false, forceRender: true, children: _jsx("p", { className: "text-sm text-gray-500", children: t("feature_coming_soon") }) }))] }));
@@ -1 +1 @@
1
- {"version":3,"file":"ManualAssignPopover.d.ts","sourceRoot":"","sources":["../../../src/components/thread/ManualAssignPopover.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAsBzC,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,UAAU,wBAAwB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;CACvC;AA0ED,QAAA,MAAM,mBAAmB,GAAI,wFAO1B,wBAAwB,4CA+P1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"ManualAssignPopover.d.ts","sourceRoot":"","sources":["../../../src/components/thread/ManualAssignPopover.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAsBzC,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,UAAU,wBAAwB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;CACvC;AA0ED,QAAA,MAAM,mBAAmB,GAAI,wFAO1B,wBAAwB,4CAyP1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -116,14 +116,12 @@ const ManualAssignPopover = ({ sessionId, supporter, teamId: propTeamId, childre
116
116
  .filter((item) => item.memberId !== (supporter === null || supporter === void 0 ? void 0 : supporter.id))
117
117
  .filter((item) => !excludeCurrentUser || item.memberId !== authUserID)
118
118
  .sort((supporterA, supporterB) => {
119
- const isSupporterACurrentUser = supporterA.memberId === authUserID;
120
- const isSupporterBCurrentUser = supporterB.memberId === authUserID;
121
- if (isSupporterACurrentUser !== isSupporterBCurrentUser) {
122
- return isSupporterACurrentUser ? -1 : 1;
123
- }
124
- return supporterA.displayName.localeCompare(supporterB.displayName, "vi", {
125
- sensitivity: "base",
126
- });
119
+ // Online first, then A-Z by display name; the viewer is not pinned.
120
+ const onlineA = supporterA.status === "ONLINE";
121
+ const onlineB = supporterB.status === "ONLINE";
122
+ if (onlineA !== onlineB)
123
+ return onlineA ? -1 : 1;
124
+ return supporterA.displayName.localeCompare(supporterB.displayName, "vi", { sensitivity: "base" });
127
125
  })
128
126
  .map((item) => (_jsx(SupporterItem, { supporter: item, onClick: handleSelectAgent, isCurrentUser: item.memberId === authUserID }, item.memberId))) })) : (_jsx("div", { className: "flex items-center justify-center py-8", children: _jsx("span", { className: "text-sm text-gray-400", children: t("manual_assign_no_results") }) })) })] }));
129
127
  const triggerNode = children !== null && children !== void 0 ? children : (_jsxs("button", { type: "button", "aria-label": t("manual_assign_button_reassign"), className: clsx("flex items-center border border-gray-200 rounded-lg p-1 gap-1 bg-transparent transition-opacity focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary-200", isSubmitting
@@ -1 +1 @@
1
- {"version":3,"file":"SessionDetailCard.d.ts","sourceRoot":"","sources":["../../../src/components/thread/SessionDetailCard.tsx"],"names":[],"mappings":"AAyBA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAsD/C,eAAO,MAAM,iBAAiB,GAAI,wBAG/B;IACD,OAAO,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC;CACnB,4CAoNA,CAAC"}
1
+ {"version":3,"file":"SessionDetailCard.d.ts","sourceRoot":"","sources":["../../../src/components/thread/SessionDetailCard.tsx"],"names":[],"mappings":"AAyBA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAsD/C,eAAO,MAAM,iBAAiB,GAAI,wBAG/B;IACD,OAAO,EAAE,gBAAgB,CAAC;IAC1B,QAAQ,EAAE,OAAO,CAAC;CACnB,4CAqNA,CAAC"}
@@ -9,7 +9,7 @@ import ManualAssignPopover from "./ManualAssignPopover";
9
9
  import SessionTagPicker from "./SessionTagPicker";
10
10
  import SessionLabelRow, { readOnlyValueClass, sessionFieldClass } from "./SessionLabelRow";
11
11
  import EndSessionConfirm from "./EndSessionConfirm";
12
- import { formatSessionDate, formatSessionTime } from "./sessionDateFormat";
12
+ import { formatSessionDate, formatSessionRange } from "./sessionDateFormat";
13
13
  import { useGetLabelSession } from "../../hooks/session/useGetLabelSession";
14
14
  import { useUpdateSessionInfo } from "../../hooks/session/useUpdateSessionInfo";
15
15
  import { useSessionFieldAutosave, } from "../../hooks/session/useSessionFieldAutosave";
@@ -92,9 +92,9 @@ export const SessionDetailCard = ({ session, isActive, }) => {
92
92
  };
93
93
  return (_jsxs("div", { className: `flex flex-col gap-3 ${isActive ? "" : "rounded-lg border border-gray-50 p-3"}`, "data-cp-name": "SessionDetailCard", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm font-bold text-gray-900", children: t("session_label", { order: session.order }) }), _jsx("span", { className: "text-xs text-gray-600", children: isActive
94
94
  ? t("session_started_at", {
95
- time: formatSessionTime(session.createdDate),
95
+ time: formatSessionDate(session.createdDate),
96
96
  })
97
- : formatSessionDate(session.closedDate || session.createdDate) }), _jsx("span", { className: "flex-1" }), isActive ? (_jsx("span", { className: "inline-flex h-[22px] items-center rounded-full bg-success-25 px-2 text-xs font-medium text-success-900", children: t("session_active") })) : (_jsx(TintedAvatar, { name: ((_b = session.supporter) === null || _b === void 0 ? void 0 : _b.fullName) || "A", src: (_c = session.supporter) === null || _c === void 0 ? void 0 : _c.avatar, size: 24 }))] }), _jsxs("div", { className: "flex flex-col gap-1", children: [fieldLabel(`${ids}-tags`, t("session_tags_label")), readOnly && labels.labels.length === 0 ? (_jsx("p", { className: emptyValueClass, children: "\u2014" })) : (_jsxs("div", { className: "divide-y divide-gray-50 rounded-lg border border-gray-50", children: [!readOnly && (_jsx(SessionTagPicker, { labelId: `${ids}-tags`, available: availableLabels !== null && availableLabels !== void 0 ? availableLabels : [], selectedIds: selectedLabelIds, onChange: labels.setLabelIds })), labels.labels.map((label) => {
97
+ : formatSessionRange(session.createdDate, session.closedDate) }), _jsx("span", { className: "flex-1" }), isActive ? (_jsx("span", { className: "inline-flex h-[22px] items-center rounded-full bg-success-25 px-2 text-xs font-medium text-success-900", children: t("session_active") })) : (_jsx(TintedAvatar, { name: ((_b = session.supporter) === null || _b === void 0 ? void 0 : _b.fullName) || "A", src: (_c = session.supporter) === null || _c === void 0 ? void 0 : _c.avatar, size: 24 }))] }), _jsxs("div", { className: "flex flex-col gap-1", children: [fieldLabel(`${ids}-tags`, t("session_tags_label")), readOnly && labels.labels.length === 0 ? (_jsx("p", { className: emptyValueClass, children: "\u2014" })) : (_jsxs("div", { className: "divide-y divide-gray-50 rounded-lg border border-gray-50", children: [!readOnly && (_jsx(SessionTagPicker, { labelId: `${ids}-tags`, available: availableLabels !== null && availableLabels !== void 0 ? availableLabels : [], selectedIds: selectedLabelIds, selectedNames: selectedLabelIds.map((id) => { var _a; return (_a = labelNames.get(id)) !== null && _a !== void 0 ? _a : ""; }), onChange: labels.setLabelIds })), labels.labels.map((label) => {
98
98
  var _a;
99
99
  return (_jsx(SessionLabelRow, { name: (_a = labelNames.get(label.id)) !== null && _a !== void 0 ? _a : "", note: label.note, readOnly: readOnly, onNoteChange: (value) => labels.setNote(label.id, value), onRemove: () => labels.setLabelIds(selectedLabelIds.filter((id) => id !== label.id)) }, label.id));
100
100
  })] }))] }), session.issueDetail && (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("span", { className: fieldLabelClass, children: t("session_issue_detail_label") }), _jsx("p", { className: readOnlyValueClass, "data-testid": "session-legacy-issue", children: session.issueDetail })] })), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsxs("div", { className: "flex items-center justify-between", children: [fieldLabel(`${ids}-note`, t("session_note_label")), !readOnly && _jsx(SaveStatus, { status: saveStatus, onRetry: retrySave })] }), readOnly ? (_jsx("p", { className: ((_d = session.note) === null || _d === void 0 ? void 0 : _d.trim()) ? readOnlyValueClass : emptyValueClass, "data-testid": "session-note-text", children: ((_e = session.note) === null || _e === void 0 ? void 0 : _e.trim()) ? session.note : "—" })) : (_jsx(TextArea, { id: `${ids}-note`, value: note.value, onChange: (e) => note.setValue(e.target.value), placeholder: t("session_note_placeholder"), className: sessionFieldClass, autoSize: { minRows: 2, maxRows: 4 } }))] }), isActive && (_jsxs(_Fragment, { children: [session.status !== SessionStatus.UNASSIGNED &&
@@ -1 +1 @@
1
- {"version":3,"file":"SessionSection.d.ts","sourceRoot":"","sources":["../../../src/components/thread/SessionSection.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAoF7B,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,QAAA,MAAM,cAAc,GAAI,0CAIrB,mBAAmB,4CAwCrB,CAAC;AAEF,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"SessionSection.d.ts","sourceRoot":"","sources":["../../../src/components/thread/SessionSection.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,iBAAiB,EAAE,CAAC;AA4E7B,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,QAAA,MAAM,cAAc,GAAI,0CAIrB,mBAAmB,4CAwCrB,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -4,15 +4,9 @@ import { Spin } from "antd";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import { SessionDetailCard } from "./SessionDetailCard";
6
6
  import { formatSessionDuration } from "./sessionDuration";
7
+ import { formatSessionRange } from "./sessionDateFormat";
7
8
  export { SessionDetailCard };
8
9
  const MAX_VISIBLE_TAGS = 2;
9
- const pad = (value) => String(value).padStart(2, "0");
10
- const formatDayMonth = (dateString) => {
11
- if (!dateString)
12
- return "";
13
- const date = new Date(dateString);
14
- return `${pad(date.getDate())}/${pad(date.getMonth() + 1)}`;
15
- };
16
10
  // One row per past session: order, date and duration, then tags and handler.
17
11
  const ClosedSessionItem = ({ session, expandedSessionId, onToggleExpand, }) => {
18
12
  var _a, _b;
@@ -23,10 +17,10 @@ const ClosedSessionItem = ({ session, expandedSessionId, onToggleExpand, }) => {
23
17
  }
24
18
  const tags = (_a = session.labels) !== null && _a !== void 0 ? _a : [];
25
19
  const duration = formatSessionDuration(session.createdDate, session.closedDate, t);
26
- const dateText = [formatDayMonth(session.closedDate || session.createdDate), duration]
20
+ const dateText = [formatSessionRange(session.createdDate, session.closedDate), duration]
27
21
  .filter(Boolean)
28
22
  .join(" · ");
29
- return (_jsxs("button", { type: "button", "aria-expanded": false, className: "flex w-full flex-col gap-1 border-t border-gray-25 py-2.5 text-left hover:bg-gray-5", onClick: () => onToggleExpand(session.id), "data-testid": "past-session-row", children: [_jsxs("span", { className: "flex items-center justify-between gap-2 text-[13px]", children: [_jsx("span", { className: "font-semibold text-gray-900", children: t("session_label", { order: session.order }) }), _jsx("span", { className: "text-gray-600", children: dateText })] }), _jsxs("span", { className: "flex min-w-0 items-center gap-1.5 text-xs text-gray-600", children: [tags.slice(0, MAX_VISIBLE_TAGS).map((label) => (_jsx("span", { className: "inline-flex h-5 max-w-[120px] shrink-0 items-center truncate rounded-full bg-[var(--dc-color-neutral-surface)] px-2 font-medium text-gray-900", children: label.name }, label.id))), tags.length > MAX_VISIBLE_TAGS && (_jsxs("span", { className: "shrink-0", children: ["+", tags.length - MAX_VISIBLE_TAGS] })), _jsx("span", { className: "truncate", children: (_b = session.supporter) === null || _b === void 0 ? void 0 : _b.fullName })] })] }));
23
+ return (_jsxs("button", { type: "button", "aria-expanded": false, className: "flex w-full flex-col gap-1 border-t border-gray-25 py-2.5 text-left hover:bg-gray-5", onClick: () => onToggleExpand(session.id), "data-testid": "past-session-row", children: [_jsxs("span", { className: "flex items-center justify-between gap-2 text-[13px]", children: [_jsx("span", { className: "font-semibold text-gray-900", children: t("session_label", { order: session.order }) }), _jsx("span", { className: "min-w-0 truncate text-gray-600", children: dateText })] }), _jsxs("span", { className: "flex min-w-0 items-center gap-1.5 text-xs text-gray-600", children: [tags.slice(0, MAX_VISIBLE_TAGS).map((label) => (_jsx("span", { className: "inline-flex h-5 max-w-[120px] shrink-0 items-center truncate rounded-full bg-[var(--dc-color-neutral-surface)] px-2 font-medium text-gray-900", children: label.name }, label.id))), tags.length > MAX_VISIBLE_TAGS && (_jsxs("span", { className: "shrink-0", children: ["+", tags.length - MAX_VISIBLE_TAGS] })), _jsx("span", { className: "truncate", children: (_b = session.supporter) === null || _b === void 0 ? void 0 : _b.fullName })] })] }));
30
24
  };
31
25
  const SessionSection = ({ sessions, isLoading, isFetchingMore = false, }) => {
32
26
  const { t } = useTranslation("common");
@@ -3,8 +3,10 @@ interface SessionTagPickerProps {
3
3
  labelId: string;
4
4
  available: ILabelResponse[];
5
5
  selectedIds: string[];
6
+ /** Names of the picked tags, shown inside the field. */
7
+ selectedNames?: string[];
6
8
  onChange: (ids: string[]) => void;
7
9
  }
8
- declare const SessionTagPicker: ({ labelId, available, selectedIds, onChange, }: SessionTagPickerProps) => import("react/jsx-runtime").JSX.Element;
10
+ declare const SessionTagPicker: ({ labelId, available, selectedIds, selectedNames, onChange, }: SessionTagPickerProps) => import("react/jsx-runtime").JSX.Element;
9
11
  export default SessionTagPicker;
10
12
  //# sourceMappingURL=SessionTagPicker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SessionTagPicker.d.ts","sourceRoot":"","sources":["../../../src/components/thread/SessionTagPicker.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACnC;AAMD,QAAA,MAAM,gBAAgB,GAAI,gDAKvB,qBAAqB,4CAkHvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"SessionTagPicker.d.ts","sourceRoot":"","sources":["../../../src/components/thread/SessionTagPicker.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACnC;AAMD,QAAA,MAAM,gBAAgB,GAAI,+DAMvB,qBAAqB,4CAoIvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}