@droppii-org/chat-sdk 0.8.1 → 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.
- package/dist/components/canned-response/cannedTrigger.d.ts +2 -0
- package/dist/components/canned-response/cannedTrigger.d.ts.map +1 -0
- package/dist/components/canned-response/cannedTrigger.js +3 -0
- package/dist/components/canned-response/insertCannedContent.js +2 -2
- package/dist/components/conversation/ConversationByGroupItem.js +1 -1
- package/dist/components/conversation/ConversationBySessionItem.js +4 -4
- package/dist/components/conversation/internalNotePreview.d.ts +1 -1
- package/dist/components/conversation/internalNotePreview.d.ts.map +1 -1
- package/dist/components/conversation/internalNotePreview.js +22 -3
- package/dist/components/conversation/rowTime.d.ts +2 -2
- package/dist/components/conversation/rowTime.d.ts.map +1 -1
- package/dist/components/conversation/rowTime.js +2 -4
- package/dist/components/conversation-detail/ConversationDetailInput.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationDetailInput.js +8 -3
- package/dist/components/conversation-detail/ConversationMessageList.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationMessageList.js +6 -3
- package/dist/components/conversation-detail/bot/BotMenuSheet.d.ts.map +1 -1
- package/dist/components/conversation-detail/bot/BotMenuSheet.js +1 -1
- package/dist/components/conversation-inbox/ConversationInboxList.d.ts.map +1 -1
- package/dist/components/conversation-inbox/ConversationInboxList.js +4 -0
- package/dist/components/conversation-inbox/InboxBootStatus.d.ts.map +1 -1
- package/dist/components/conversation-inbox/InboxBootStatus.js +10 -2
- package/dist/components/group/CreateGroupForm.d.ts.map +1 -1
- package/dist/components/group/CreateGroupForm.js +2 -1
- package/dist/components/group/CreateGroupFormCrmView.d.ts.map +1 -1
- package/dist/components/group/CreateGroupFormCrmView.js +1 -1
- package/dist/components/group/GroupMemberPickerCrm.d.ts.map +1 -1
- package/dist/components/group/GroupMemberPickerCrm.js +1 -1
- package/dist/components/media-collection/FileCollection.d.ts.map +1 -1
- package/dist/components/media-collection/FileCollection.js +2 -1
- package/dist/components/media-collection/ImageCollection.d.ts.map +1 -1
- package/dist/components/media-collection/ImageCollection.js +2 -1
- package/dist/components/media-collection/LinkCollection.d.ts.map +1 -1
- package/dist/components/media-collection/LinkCollection.js +14 -26
- package/dist/components/media-collection/VideoCollection.d.ts.map +1 -1
- package/dist/components/media-collection/VideoCollection.js +2 -1
- package/dist/components/media-resources/ResourceScrollContainer.d.ts.map +1 -1
- package/dist/components/media-resources/ResourceScrollContainer.js +34 -2
- package/dist/components/message/GroupMembersDrawer.d.ts.map +1 -1
- package/dist/components/message/GroupMembersDrawer.js +2 -3
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +15 -4
- package/dist/components/message/footer/ActionBar.d.ts.map +1 -1
- package/dist/components/message/footer/ActionBar.js +10 -44
- package/dist/components/message/footer/CannedResponsePlugin.d.ts.map +1 -1
- package/dist/components/message/footer/CannedResponsePlugin.js +3 -2
- package/dist/components/message/footer/EnterHandler.d.ts.map +1 -1
- package/dist/components/message/footer/EnterHandler.js +10 -47
- package/dist/components/message/footer/FilePreview.d.ts.map +1 -1
- package/dist/components/message/footer/FilePreview.js +2 -1
- package/dist/components/message/footer/LinkInputPreview.d.ts +1 -1
- package/dist/components/message/footer/LinkInputPreview.d.ts.map +1 -1
- package/dist/components/message/footer/LinkInputPreview.js +8 -1
- package/dist/components/message/footer/MediaUploadButtons.d.ts.map +1 -1
- package/dist/components/message/footer/MediaUploadButtons.js +4 -7
- package/dist/components/message/footer/index.d.ts.map +1 -1
- package/dist/components/message/footer/index.js +57 -16
- package/dist/components/message/footer/mention/useMentionOptions.d.ts.map +1 -1
- package/dist/components/message/footer/mention/useMentionOptions.js +2 -6
- package/dist/components/message/footer/resetEditorAfterSend.d.ts +7 -0
- package/dist/components/message/footer/resetEditorAfterSend.d.ts.map +1 -0
- package/dist/components/message/footer/resetEditorAfterSend.js +62 -0
- package/dist/components/message/groupMemberMenuCrm.d.ts +4 -4
- package/dist/components/message/groupMemberMenuCrm.d.ts.map +1 -1
- package/dist/components/message/groupMemberMenuCrm.js +73 -60
- package/dist/components/message/item/SystemLogMessage.d.ts.map +1 -1
- package/dist/components/message/item/SystemLogMessage.js +5 -2
- package/dist/components/search-conversation/SearchConversationAsGroups.js +1 -1
- package/dist/components/search-conversation/SearchConversationAsMessages.js +1 -1
- package/dist/components/search-conversation/SearchConversationMyInbox.js +1 -1
- package/dist/components/thread/GroupInfoBodyCrm.d.ts.map +1 -1
- package/dist/components/thread/GroupInfoBodyCrm.js +2 -2
- package/dist/components/thread/GroupThreadInfo.d.ts.map +1 -1
- package/dist/components/thread/GroupThreadInfo.js +2 -6
- package/dist/components/thread/ManualAssignPopover.d.ts.map +1 -1
- package/dist/components/thread/ManualAssignPopover.js +6 -8
- package/dist/components/thread/SessionDetailCard.d.ts.map +1 -1
- package/dist/components/thread/SessionDetailCard.js +3 -3
- package/dist/components/thread/SessionSection.d.ts.map +1 -1
- package/dist/components/thread/SessionSection.js +3 -9
- package/dist/components/thread/SessionTagPicker.d.ts +3 -1
- package/dist/components/thread/SessionTagPicker.d.ts.map +1 -1
- package/dist/components/thread/SessionTagPicker.js +2 -2
- package/dist/components/thread/sessionDateFormat.d.ts +2 -0
- package/dist/components/thread/sessionDateFormat.d.ts.map +1 -1
- package/dist/components/thread/sessionDateFormat.js +6 -0
- package/dist/constants/dateFormat.d.ts +2 -0
- package/dist/constants/dateFormat.d.ts.map +1 -0
- package/dist/constants/dateFormat.js +2 -0
- package/dist/hooks/common/useFetchUrlMetadata.d.ts +1 -0
- package/dist/hooks/common/useFetchUrlMetadata.d.ts.map +1 -1
- package/dist/hooks/conversation/useBotFlow.d.ts.map +1 -1
- package/dist/hooks/conversation/useBotFlow.js +64 -12
- package/dist/hooks/conversation/useCloseBotSession.d.ts +2 -0
- package/dist/hooks/conversation/useCloseBotSession.d.ts.map +1 -1
- package/dist/hooks/conversation/useCloseBotSession.js +17 -1
- package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
- package/dist/hooks/global/useGlobalEvent.js +148 -16
- package/dist/hooks/global/useLoginHealth.d.ts +3 -0
- package/dist/hooks/global/useLoginHealth.d.ts.map +1 -0
- package/dist/hooks/global/useLoginHealth.js +55 -0
- package/dist/hooks/group/useCreateGroup.d.ts.map +1 -1
- package/dist/hooks/group/useCreateGroup.js +75 -6
- package/dist/hooks/init/useChatBootPhase.d.ts +2 -0
- package/dist/hooks/init/useChatBootPhase.d.ts.map +1 -1
- package/dist/hooks/init/useChatBootPhase.js +11 -6
- package/dist/hooks/message/useMessage.d.ts.map +1 -1
- package/dist/hooks/message/useMessage.js +97 -28
- package/dist/hooks/message/usePinnedMessages.d.ts.map +1 -1
- package/dist/hooks/message/usePinnedMessages.js +13 -2
- package/dist/hooks/message/useRevokeMessage.d.ts.map +1 -1
- package/dist/hooks/message/useRevokeMessage.js +25 -0
- package/dist/hooks/message/useSendMessage.d.ts +15 -12
- package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
- package/dist/hooks/message/useSendMessage.js +199 -133
- package/dist/hooks/search/useSearchMessage.d.ts.map +1 -1
- package/dist/hooks/search/useSearchMessage.js +57 -3
- package/dist/hooks/session/useConversationSessionState.d.ts.map +1 -1
- package/dist/hooks/session/useConversationSessionState.js +4 -1
- package/dist/hooks/session/useSessionLatestPreview.d.ts.map +1 -1
- package/dist/hooks/session/useSessionLatestPreview.js +34 -4
- package/dist/hooks/user/useAuth.d.ts +1 -1
- package/dist/hooks/user/useAuth.d.ts.map +1 -1
- package/dist/hooks/user/useAuth.js +31 -15
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/locales/vi/boot.json +5 -1
- package/dist/locales/vi/common.json +34 -15
- package/dist/locales/vi/conversation-inbox.json +2 -1
- package/dist/screens/conversation-detail/index.d.ts.map +1 -1
- package/dist/screens/conversation-detail/index.js +6 -0
- package/dist/screens/desk-message/DeskBootCard.d.ts.map +1 -1
- package/dist/screens/desk-message/DeskBootCard.js +6 -4
- package/dist/store/boot.d.ts +5 -0
- package/dist/store/boot.d.ts.map +1 -1
- package/dist/store/boot.js +11 -1
- package/dist/store/conversation.d.ts.map +1 -1
- package/dist/store/conversation.js +5 -1
- package/dist/store/type.d.ts +3 -1
- package/dist/store/type.d.ts.map +1 -1
- package/dist/styles/global.css +1 -1
- package/dist/types/chat.d.ts +1 -1
- package/dist/types/chat.d.ts.map +1 -1
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/common.js +4 -1
- package/dist/utils/fileValidation.d.ts +7 -0
- package/dist/utils/fileValidation.d.ts.map +1 -1
- package/dist/utils/fileValidation.js +37 -13
- package/dist/utils/latestMessagePreviewable.d.ts +2 -0
- package/dist/utils/latestMessagePreviewable.d.ts.map +1 -0
- package/dist/utils/latestMessagePreviewable.js +18 -0
- package/dist/utils/mentionMembers.d.ts +3 -0
- package/dist/utils/mentionMembers.d.ts.map +1 -0
- package/dist/utils/mentionMembers.js +29 -0
- package/dist/utils/messageLog.d.ts +2 -2
- package/dist/utils/messageLog.d.ts.map +1 -1
- package/dist/utils/messageLog.js +129 -40
- package/dist/utils/notifiableMessage.d.ts +7 -0
- package/dist/utils/notifiableMessage.d.ts.map +1 -0
- package/dist/utils/notifiableMessage.js +26 -0
- package/dist/utils/withSdkTimeout.d.ts +11 -0
- package/dist/utils/withSdkTimeout.d.ts.map +1 -0
- package/dist/utils/withSdkTimeout.js +30 -0
- 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
|
|
28
|
-
*
|
|
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,
|
|
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,
|
|
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
|
|
7
|
-
*
|
|
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,
|
|
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
|
-
|
|
24
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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;
|
|
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
|
|
10
|
-
const
|
|
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
|
}
|
|
@@ -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("
|
|
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("
|
|
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("
|
|
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,
|
|
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") }),
|
|
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,
|
|
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:
|
|
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" })] })] })),
|
|
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,
|
|
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
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
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,
|
|
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,
|
|
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:
|
|
95
|
+
time: formatSessionDate(session.createdDate),
|
|
96
96
|
})
|
|
97
|
-
:
|
|
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;
|
|
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 = [
|
|
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,
|
|
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"}
|