@droppii-org/chat-sdk 0.7.6 → 0.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/conversation/ThreadCard.d.ts +2 -1
- package/dist/components/conversation/ThreadCard.d.ts.map +1 -1
- package/dist/components/conversation/ThreadCard.js +2 -2
- package/dist/components/conversation-detail/ConversationDetailHeader.d.ts +5 -1
- package/dist/components/conversation-detail/ConversationDetailHeader.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationDetailHeader.js +3 -3
- package/dist/components/conversation-detail/ConversationMoreOptionPanel.d.ts.map +1 -1
- package/dist/components/conversation-detail/ConversationMoreOptionPanel.js +3 -1
- package/dist/components/conversation-detail/ThreadProfilePanel.d.ts +5 -1
- package/dist/components/conversation-detail/ThreadProfilePanel.d.ts.map +1 -1
- package/dist/components/conversation-detail/ThreadProfilePanel.js +13 -3
- package/dist/components/conversation-detail/profile/PinThreadLimitModal.d.ts +7 -0
- package/dist/components/conversation-detail/profile/PinThreadLimitModal.d.ts.map +1 -0
- package/dist/components/conversation-detail/profile/PinThreadLimitModal.js +14 -0
- package/dist/components/conversation-detail/profile/ThreadProfileActionRows.d.ts +15 -0
- package/dist/components/conversation-detail/profile/ThreadProfileActionRows.d.ts.map +1 -0
- package/dist/components/conversation-detail/profile/ThreadProfileActionRows.js +20 -0
- package/dist/components/conversation-detail/profile/ThreadProfileQuickActions.d.ts +11 -0
- package/dist/components/conversation-detail/profile/ThreadProfileQuickActions.d.ts.map +1 -0
- package/dist/components/conversation-detail/profile/ThreadProfileQuickActions.js +36 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchContent.d.ts +13 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchContent.d.ts.map +1 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchContent.js +70 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchPanel.d.ts +11 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchPanel.d.ts.map +1 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchPanel.js +12 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchResultItem.d.ts +11 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchResultItem.d.ts.map +1 -0
- package/dist/components/conversation-detail/thread-search/ThreadSearchResultItem.js +24 -0
- package/dist/components/conversation-detail/thread-search/utils.d.ts +8 -0
- package/dist/components/conversation-detail/thread-search/utils.d.ts.map +1 -0
- package/dist/components/conversation-detail/thread-search/utils.js +17 -0
- package/dist/components/conversation-inbox/ConversationInboxItem.d.ts +3 -1
- package/dist/components/conversation-inbox/ConversationInboxItem.d.ts.map +1 -1
- package/dist/components/conversation-inbox/ConversationInboxItem.js +4 -6
- package/dist/components/conversation-inbox/ConversationInboxList.d.ts +3 -1
- package/dist/components/conversation-inbox/ConversationInboxList.d.ts.map +1 -1
- package/dist/components/conversation-inbox/ConversationInboxList.js +2 -2
- package/dist/components/conversation-inbox/ConversationThreadActions.d.ts +12 -0
- package/dist/components/conversation-inbox/ConversationThreadActions.d.ts.map +1 -0
- package/dist/components/conversation-inbox/ConversationThreadActions.js +58 -0
- package/dist/components/conversation-inbox/contact-search/ContactSearchCommunitySection.d.ts +10 -0
- package/dist/components/conversation-inbox/contact-search/ContactSearchCommunitySection.d.ts.map +1 -0
- package/dist/components/conversation-inbox/contact-search/ContactSearchCommunitySection.js +15 -0
- package/dist/components/conversation-inbox/contact-search/ContactSearchPanel.d.ts.map +1 -1
- package/dist/components/conversation-inbox/contact-search/ContactSearchPanel.js +39 -28
- package/dist/components/conversation-inbox/contact-search/constants.js +2 -2
- package/dist/components/conversation-inbox/index.d.ts +2 -2
- package/dist/components/conversation-inbox/index.d.ts.map +1 -1
- package/dist/components/conversation-inbox/index.js +1 -1
- package/dist/components/group/MemberPermissionPanel.d.ts.map +1 -1
- package/dist/components/group/MemberPermissionPanel.js +12 -23
- package/dist/components/message/toolbox/MessageToolboxMenu.d.ts +7 -0
- package/dist/components/message/toolbox/MessageToolboxMenu.d.ts.map +1 -1
- package/dist/components/message/toolbox/MessageToolboxMenu.js +1 -1
- package/dist/constants/moreOption.d.ts +1 -0
- package/dist/constants/moreOption.d.ts.map +1 -1
- package/dist/hooks/conversation/useBotFlow.d.ts.map +1 -1
- package/dist/hooks/conversation/useBotFlow.js +42 -23
- package/dist/hooks/conversation/useConversationTarget.d.ts +4 -0
- package/dist/hooks/conversation/useConversationTarget.d.ts.map +1 -0
- package/dist/hooks/conversation/useConversationTarget.js +23 -0
- package/dist/hooks/conversation/usePinConversation.d.ts +10 -0
- package/dist/hooks/conversation/usePinConversation.d.ts.map +1 -0
- package/dist/hooks/conversation/usePinConversation.js +52 -0
- package/dist/hooks/message/holdMessageHighlight.d.ts +6 -0
- package/dist/hooks/message/holdMessageHighlight.d.ts.map +1 -0
- package/dist/hooks/message/holdMessageHighlight.js +22 -0
- package/dist/hooks/message/useMessageListScroll.d.ts.map +1 -1
- package/dist/hooks/message/useMessageListScroll.js +13 -0
- package/dist/hooks/message/useSendMessage.d.ts +1 -1
- package/dist/hooks/message/useSendMessage.d.ts.map +1 -1
- package/dist/hooks/message/useSendMessage.js +358 -285
- package/dist/hooks/search/useSearchPublicGroups.d.ts +1 -0
- package/dist/hooks/search/useSearchPublicGroups.d.ts.map +1 -1
- package/dist/hooks/search/useSearchPublicGroups.js +6 -0
- package/dist/hooks/search/useSearchThreadMessages.d.ts +222 -0
- package/dist/hooks/search/useSearchThreadMessages.d.ts.map +1 -0
- package/dist/hooks/search/useSearchThreadMessages.js +60 -0
- package/dist/locales/vi/conversation-inbox.json +31 -0
- package/dist/screens/conversation-detail/index.d.ts +5 -1
- package/dist/screens/conversation-detail/index.d.ts.map +1 -1
- package/dist/screens/conversation-detail/index.js +17 -2
- package/dist/screens/conversation-inbox/index.d.ts +6 -0
- package/dist/screens/conversation-inbox/index.d.ts.map +1 -1
- package/dist/screens/conversation-inbox/index.js +3 -3
- package/dist/services/query.d.ts +3 -0
- package/dist/services/query.d.ts.map +1 -1
- package/dist/services/query.js +3 -0
- package/dist/services/routes.d.ts +2 -0
- package/dist/services/routes.d.ts.map +1 -1
- package/dist/services/routes.js +2 -0
- package/dist/store/conversation.d.ts.map +1 -1
- package/dist/store/conversation.js +10 -6
- package/dist/store/type.d.ts +3 -0
- package/dist/store/type.d.ts.map +1 -1
- package/dist/styles/global.css +1 -1
- package/dist/types/conversation.d.ts +8 -0
- package/dist/types/conversation.d.ts.map +1 -1
- package/dist/utils/common.d.ts +7 -0
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/common.js +42 -13
- package/dist/utils/sendQueue.d.ts +2 -0
- package/dist/utils/sendQueue.d.ts.map +1 -0
- package/dist/utils/sendQueue.js +14 -0
- package/package.json +1 -1
- package/dist/components/conversation-inbox/ConversationMuteSwipeAction.d.ts +0 -8
- package/dist/components/conversation-inbox/ConversationMuteSwipeAction.d.ts.map +0 -1
- package/dist/components/conversation-inbox/ConversationMuteSwipeAction.js +0 -31
|
@@ -10,7 +10,8 @@ export interface ThreadCardProps {
|
|
|
10
10
|
testId?: string;
|
|
11
11
|
muteIndicator?: ReactNode;
|
|
12
12
|
mentionIndicator?: ReactNode;
|
|
13
|
+
pinIndicator?: ReactNode;
|
|
13
14
|
}
|
|
14
|
-
declare const ThreadCard: ({ avatar, title, preview, time, unreadCount, isSelected, onClick, testId, muteIndicator, mentionIndicator, }: ThreadCardProps) => import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
declare const ThreadCard: ({ avatar, title, preview, time, unreadCount, isSelected, onClick, testId, muteIndicator, mentionIndicator, pinIndicator, }: ThreadCardProps) => import("react/jsx-runtime").JSX.Element;
|
|
15
16
|
export default ThreadCard;
|
|
16
17
|
//# sourceMappingURL=ThreadCard.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreadCard.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ThreadCard.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAqBvC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,gBAAgB,CAAC,EAAE,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"ThreadCard.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ThreadCard.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAqBvC,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAC7B,YAAY,CAAC,EAAE,SAAS,CAAC;CAC1B;AAED,QAAA,MAAM,UAAU,GAAI,4HAYjB,eAAe,4CAgDjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -7,10 +7,10 @@ const UnreadBadge = ({ count }) => {
|
|
|
7
7
|
const isWide = label.length > 1;
|
|
8
8
|
return (_jsx("span", { className: clsx("inline-flex h-5 shrink-0 items-center justify-center rounded-[32px] border-2 border-white bg-gradient-danger-light px-[3px] text-center text-[12px] font-semibold leading-[160%] text-white", isWide ? "min-w-8" : "min-w-5"), "data-cp-name": "UnreadBadge", children: label }));
|
|
9
9
|
};
|
|
10
|
-
const ThreadCard = ({ avatar, title, preview, time, unreadCount = 0, isSelected = false, onClick, testId, muteIndicator, mentionIndicator, }) => {
|
|
10
|
+
const ThreadCard = ({ avatar, title, preview, time, unreadCount = 0, isSelected = false, onClick, testId, muteIndicator, mentionIndicator, pinIndicator, }) => {
|
|
11
11
|
const hasUnread = unreadCount > 0;
|
|
12
12
|
return (_jsxs("button", { type: "button", onClick: onClick, "data-testid": testId, "data-cp-name": "ThreadCard", className: clsx("relative flex w-full shrink-0 items-start gap-2 border-b border-gray-25 p-3 text-left transition-colors hover:bg-[#f5f5f5] focus:outline-none focus-visible:ring-2 focus-visible:ring-chat-ring", isSelected ? "bg-blue-50" : "bg-white"), children: [isSelected && (_jsx("span", { className: "absolute bottom-0 left-0 top-0 w-1 bg-blue-500" })), avatar, _jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [_jsxs("div", { className: "flex min-h-[25.6px] items-center justify-between gap-1", children: [_jsx("div", { className: "min-w-0 flex-1", children: title }), muteIndicator, time && (_jsx("span", { className: "shrink-0 text-[12px] font-normal leading-[160%] text-gray-400 [font-feature-settings:'liga'_off,'clig'_off]", children: time }))] }), _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("p", { className: clsx("min-w-0 flex-1 truncate text-[14px] leading-[160%] [font-feature-settings:'liga'_off,'clig'_off]", hasUnread
|
|
13
13
|
? "font-[510] text-black"
|
|
14
|
-
: "font-normal tracking-[0.14px] text-gray-600"), children: preview }), mentionIndicator, hasUnread && _jsx(UnreadBadge, { count: unreadCount })] })] })] }));
|
|
14
|
+
: "font-normal tracking-[0.14px] text-gray-600"), children: preview }), mentionIndicator, pinIndicator, hasUnread && _jsx(UnreadBadge, { count: unreadCount })] })] })] }));
|
|
15
15
|
};
|
|
16
16
|
export default ThreadCard;
|
|
@@ -3,7 +3,11 @@ export interface ConversationDetailHeaderProps {
|
|
|
3
3
|
conversation: ConversationItem;
|
|
4
4
|
onBack?: () => void;
|
|
5
5
|
onProfileClick?: () => void;
|
|
6
|
+
/** Shows the ☰ profile icon on the right; it opens the same panel. */
|
|
7
|
+
onProfileIconClick?: () => void;
|
|
8
|
+
/** Shows the search icon left of ☰; it opens search in this thread. */
|
|
9
|
+
onSearchClick?: () => void;
|
|
6
10
|
}
|
|
7
|
-
declare const ConversationDetailHeader: ({ conversation, onBack, onProfileClick, }: ConversationDetailHeaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
declare const ConversationDetailHeader: ({ conversation, onBack, onProfileClick, onProfileIconClick, onSearchClick, }: ConversationDetailHeaderProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
12
|
export default ConversationDetailHeader;
|
|
9
13
|
//# sourceMappingURL=ConversationDetailHeader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationDetailHeader.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailHeader.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGrE,MAAM,WAAW,6BAA6B;IAC5C,YAAY,EAAE,gBAAgB,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ConversationDetailHeader.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailHeader.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGrE,MAAM,WAAW,6BAA6B;IAC5C,YAAY,EAAE,gBAAgB,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,sEAAsE;IACtE,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAyBD,QAAA,MAAM,wBAAwB,GAAI,8EAM/B,6BAA6B,4CA0D/B,CAAC;AAEF,eAAe,wBAAwB,CAAC"}
|
|
@@ -5,11 +5,11 @@ import { Icon } from "../../components/icon";
|
|
|
5
5
|
import ConversationPeerAvatar from "../../components/conversation-inbox/ConversationPeerAvatar";
|
|
6
6
|
import ConversationInboxTitle from "../../components/conversation-inbox/ConversationInboxTitle";
|
|
7
7
|
import { useConversationPeerIdentity } from "../../hooks/conversation/useConversationPeerIdentity";
|
|
8
|
-
const HeaderIconButton = ({ icon, onClick, testId, }) => (_jsx("button", { type: "button", onClick: onClick, "data-testid": testId, "data-cp-name": "HeaderIconButton", className: "flex shrink-0 cursor-pointer items-center justify-center p-2 text-[var(--dc-color-nav-icon)]", children: _jsx(Icon, { icon: icon, size: 24 }) }));
|
|
9
|
-
const ConversationDetailHeader = ({ conversation, onBack, onProfileClick, }) => {
|
|
8
|
+
const HeaderIconButton = ({ icon, onClick, testId, ariaLabel, }) => (_jsx("button", { type: "button", onClick: onClick, "data-testid": testId, "aria-label": ariaLabel, "data-cp-name": "HeaderIconButton", className: "flex shrink-0 cursor-pointer items-center justify-center p-2 text-[var(--dc-color-nav-icon)]", children: _jsx(Icon, { icon: icon, size: 24 }) }));
|
|
9
|
+
const ConversationDetailHeader = ({ conversation, onBack, onProfileClick, onProfileIconClick, onSearchClick, }) => {
|
|
10
10
|
const { t } = useTranslation("conversation-inbox");
|
|
11
11
|
const { displayName, avatarUrl, peerType, badgeLabel } = useConversationPeerIdentity(conversation);
|
|
12
12
|
const subtitle = t("thread_detail.profile_hint");
|
|
13
|
-
return (_jsxs("div", { "data-testid": "conversation-detail-header", "data-cp-name": "ConversationDetailHeader", className: "flex w-full cursor-default items-center border-b border-gray-25 bg-white p-2 shadow-inset-gray-divider", children: [_jsx(HeaderIconButton, { icon: "arrow-left-o", onClick: onBack, testId: "conversation-detail-back" }), _jsxs("div", { className: "flex min-w-0 flex-1 cursor-pointer items-center gap-2 px-1", "data-testid": "conversation-detail-profile", onClick: onProfileClick, children: [_jsx(ConversationPeerAvatar, { peerType: peerType, displayName: displayName, avatarUrl: avatarUrl, badgeLabel: badgeLabel }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(ConversationInboxTitle, { peerType: peerType, displayName: displayName }), _jsx("p", { className: "truncate text-[10px] font-normal leading-[160%] tracking-[0.1px] text-gray-600 [font-feature-settings:'liga'_off,'clig'_off]", children: subtitle })] })] })] }));
|
|
13
|
+
return (_jsxs("div", { "data-testid": "conversation-detail-header", "data-cp-name": "ConversationDetailHeader", className: "flex w-full cursor-default items-center border-b border-gray-25 bg-white p-2 shadow-inset-gray-divider", children: [_jsx(HeaderIconButton, { icon: "arrow-left-o", onClick: onBack, testId: "conversation-detail-back" }), _jsxs("div", { className: "flex min-w-0 flex-1 cursor-pointer items-center gap-2 px-1", "data-testid": "conversation-detail-profile", onClick: onProfileClick, children: [_jsx(ConversationPeerAvatar, { peerType: peerType, displayName: displayName, avatarUrl: avatarUrl, badgeLabel: badgeLabel }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(ConversationInboxTitle, { peerType: peerType, displayName: displayName }), _jsx("p", { className: "truncate text-[10px] font-normal leading-[160%] tracking-[0.1px] text-gray-600 [font-feature-settings:'liga'_off,'clig'_off]", children: subtitle })] })] }), onSearchClick && (_jsx(HeaderIconButton, { icon: "search-o", onClick: onSearchClick, testId: "conversation-detail-search-icon", ariaLabel: t("thread_detail.search.open") })), onProfileIconClick && (_jsx(HeaderIconButton, { icon: "menu-o", onClick: onProfileIconClick, testId: "conversation-detail-profile-icon", ariaLabel: t("thread_detail.profile.open") }))] }));
|
|
14
14
|
};
|
|
15
15
|
export default ConversationDetailHeader;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationMoreOptionPanel.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationMoreOptionPanel.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,gBAAgB,EAEjB,MAAM,wBAAwB,CAAC;AAGhC,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,2BAA2B,GAAI,qFAMlC,gCAAgC,
|
|
1
|
+
{"version":3,"file":"ConversationMoreOptionPanel.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationMoreOptionPanel.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,gBAAgB,EAEjB,MAAM,wBAAwB,CAAC;AAGhC,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,2BAA2B,GAAI,qFAMlC,gCAAgC,4CAqClC,CAAC;AAEF,eAAe,2BAA2B,CAAC"}
|
|
@@ -19,6 +19,8 @@ const ConversationMoreOptionPanel = ({ disabled = false, options = MORE_OPTIONS,
|
|
|
19
19
|
}
|
|
20
20
|
onSelectOption === null || onSelectOption === void 0 ? void 0 : onSelectOption(option);
|
|
21
21
|
}, [onSelectOption, onTriggerMediaInput, onTriggerDocumentInput]);
|
|
22
|
-
return (_jsx("div", { "data-testid": "conversation-more-option-panel", "data-cp-name": "ConversationMoreOptionPanel", className: "grid grid-cols-4 gap-y-5 bg-white py-5", children: options
|
|
22
|
+
return (_jsx("div", { "data-testid": "conversation-more-option-panel", "data-cp-name": "ConversationMoreOptionPanel", className: "grid grid-cols-4 gap-y-5 bg-white py-5", children: options
|
|
23
|
+
.filter((option) => option.enabled)
|
|
24
|
+
.map((option) => (_jsx(ConversationMoreOptionItem, { option: Object.assign(Object.assign({}, option), { enabled: !disabled }), onSelect: handleSelectOption }, option.key))) }));
|
|
23
25
|
};
|
|
24
26
|
export default ConversationMoreOptionPanel;
|
|
@@ -5,7 +5,11 @@ interface ThreadProfilePanelProps {
|
|
|
5
5
|
conversation: ConversationItem;
|
|
6
6
|
onClose: () => void;
|
|
7
7
|
onSelectResource: (tabKey: MediaResourceTabKey) => void;
|
|
8
|
+
/** Quick actions and action rows from the BIZ profile design. */
|
|
9
|
+
showActions?: boolean;
|
|
10
|
+
/** Wires the "Tìm tin nhắn" quick action. */
|
|
11
|
+
onSearch?: () => void;
|
|
8
12
|
}
|
|
9
|
-
declare const ThreadProfilePanel: ({ open, conversation, onClose, onSelectResource, }: ThreadProfilePanelProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
declare const ThreadProfilePanel: ({ open, conversation, onClose, onSelectResource, showActions, onSearch, }: ThreadProfilePanelProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
14
|
export default ThreadProfilePanel;
|
|
11
15
|
//# sourceMappingURL=ThreadProfilePanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreadProfilePanel.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ThreadProfilePanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"ThreadProfilePanel.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ThreadProfilePanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAc7E,UAAU,uBAAuB;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,gBAAgB,CAAC;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACxD,iEAAiE;IACjE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAID,QAAA,MAAM,kBAAkB,GAAI,2EAOzB,uBAAuB,4CAmJzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -9,20 +9,30 @@ import { PeerType } from "../../types/conversation";
|
|
|
9
9
|
import { resolvePeerBadgeColor } from "../../utils/conversation";
|
|
10
10
|
import { useConversationPeerIdentity } from "../../hooks/conversation/useConversationPeerIdentity";
|
|
11
11
|
import { useLeaveGroupAction } from "../../hooks/group/useLeaveGroupAction";
|
|
12
|
+
import { useConversationTarget } from "../../hooks/conversation/useConversationTarget";
|
|
13
|
+
import useConversationStore from "../../store/conversation";
|
|
12
14
|
import LeaveGroupBlockedModal from "./LeaveGroupBlockedModal";
|
|
13
15
|
import LeaveGroupConfirmModal from "./LeaveGroupConfirmModal";
|
|
16
|
+
import ThreadProfileQuickActions from "./profile/ThreadProfileQuickActions";
|
|
17
|
+
import ThreadProfileActionRows from "./profile/ThreadProfileActionRows";
|
|
14
18
|
const PROFILE_AVATAR_SIZE = 96;
|
|
15
|
-
const
|
|
19
|
+
const PERSON_PEER_TYPES = [PeerType.USER, PeerType.CUSTOMER];
|
|
20
|
+
const ThreadProfilePanel = ({ open, conversation, onClose, onSelectResource, showActions = false, onSearch, }) => {
|
|
21
|
+
var _a;
|
|
16
22
|
const { t } = useTranslation("conversation-inbox");
|
|
17
23
|
const { displayName, avatarUrl, peerType, badgeLabel } = useConversationPeerIdentity(conversation);
|
|
24
|
+
const isGroupThread = conversation.peerType === PeerType.GROUP;
|
|
25
|
+
const isViewOnly = useConversationStore((state) => isGroupThread && state.isViewOnlyMember);
|
|
26
|
+
const showPersonRows = PERSON_PEER_TYPES.includes((_a = conversation.peerType) !== null && _a !== void 0 ? _a : "");
|
|
27
|
+
const { isTargetActive } = useConversationTarget(conversation.conversationID, open && showActions && showPersonRows);
|
|
18
28
|
const { canLeaveGroup, isPublicGroup, isLeaving, isConfirmOpen, isBlockedOpen, openLeaveGroup, confirmLeaveGroup, closeConfirm, closeBlocked, } = useLeaveGroupAction({
|
|
19
29
|
groupID: conversation.groupID,
|
|
20
30
|
conversationID: conversation.conversationID,
|
|
21
|
-
isGroupThread
|
|
31
|
+
isGroupThread,
|
|
22
32
|
onLeft: onClose,
|
|
23
33
|
});
|
|
24
34
|
return (_jsxs(Drawer, { open: open, onClose: onClose, placement: "right", closeIcon: false, width: "100%", "data-cp-name": "ThreadProfilePanel", styles: {
|
|
25
35
|
body: { padding: 0 },
|
|
26
|
-
}, getContainer: false, forceRender: true, destroyOnHidden: true, children: [_jsxs("div", { className: "flex h-full flex-col bg-gray-25", children: [_jsxs("div", { className: "flex w-full items-center bg-white p-2", children: [_jsx("button", { type: "button", "data-testid": "thread-profile-back", className: "flex shrink-0 cursor-pointer items-center justify-center p-2 text-[var(--dc-color-nav-icon)]", onClick: onClose, children: _jsx(Icon, { icon: "arrow-left-o", size: 24 }) }), _jsx("p", { className: "min-w-0 flex-1 truncate px-2 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("thread_detail.options_title") })] }), _jsxs("div", { className: "flex flex-col items-center gap-2 bg-white px-0 py-2", children: [_jsxs("div", { className: "relative h-24 w-24 shrink-0", children: [_jsx(Avatar, { size: PROFILE_AVATAR_SIZE, src: avatarUrl || undefined, alt: displayName, className: "uppercase", children: (displayName === null || displayName === void 0 ? void 0 : displayName.charAt(0)) || "A" }), badgeLabel && (_jsx("span", { className: clsx("absolute bottom-1 right-0 flex h-[17px] items-center justify-center rounded-md border border-white px-1 text-[10px] font-semibold leading-3 text-white shadow-badge-inset", resolvePeerBadgeColor(peerType)), children: badgeLabel }))] }), _jsx("p", { className: "w-full truncate text-center text-[18px] font-bold leading-[1.6] text-gray-900", children: displayName })] }), _jsx("div", { className: "flex flex-col px-3 py-1.5", children: _jsx(MediaEntryCard, { onSelect: onSelectResource }) }), canLeaveGroup && (_jsx("div", { className: "flex flex-col px-3 py-1.5", children: _jsx("div", { className: "overflow-hidden rounded-xl bg-white", children: _jsxs("button", { type: "button", "data-testid": "thread-profile-leave-group", className: "flex w-full cursor-pointer items-center gap-2 p-4 text-danger-400", onClick: openLeaveGroup, children: [_jsx(Icon, { icon: "logout-o", size: 24 }), _jsx("span", { className: "text-[16px] font-medium leading-[1.6]", children: t("thread_detail.leave_group.action") })] }) }) }))] }), _jsx(LeaveGroupConfirmModal, { open: isConfirmOpen, loading: isLeaving, isPublicGroup: isPublicGroup, onCancel: closeConfirm, onConfirm: confirmLeaveGroup }), _jsx(LeaveGroupBlockedModal, { open: isBlockedOpen, onClose: closeBlocked })] }));
|
|
36
|
+
}, getContainer: false, forceRender: true, destroyOnHidden: true, children: [_jsxs("div", { className: clsx("flex h-full flex-col bg-gray-25", showActions && "overflow-y-auto"), children: [_jsxs("div", { className: clsx("flex w-full items-center bg-white p-2", showActions && "sticky top-0 z-10 shrink-0"), children: [_jsx("button", { type: "button", "data-testid": "thread-profile-back", className: "flex shrink-0 cursor-pointer items-center justify-center p-2 text-[var(--dc-color-nav-icon)]", onClick: onClose, children: _jsx(Icon, { icon: "arrow-left-o", size: 24 }) }), _jsx("p", { className: "min-w-0 flex-1 truncate px-2 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("thread_detail.options_title") })] }), _jsxs("div", { className: "flex flex-col items-center gap-2 bg-white px-0 py-2", children: [_jsxs("div", { className: "relative h-24 w-24 shrink-0", children: [_jsx(Avatar, { size: PROFILE_AVATAR_SIZE, src: avatarUrl || undefined, alt: displayName, className: "uppercase", children: (displayName === null || displayName === void 0 ? void 0 : displayName.charAt(0)) || "A" }), badgeLabel && (_jsx("span", { className: clsx("absolute bottom-1 right-0 flex h-[17px] items-center justify-center rounded-md border border-white px-1 text-[10px] font-semibold leading-3 text-white shadow-badge-inset", resolvePeerBadgeColor(peerType)), children: badgeLabel }))] }), _jsx("p", { className: "w-full truncate text-center text-[18px] font-bold leading-[1.6] text-gray-900", children: displayName }), showActions && (_jsx(ThreadProfileQuickActions, { conversation: conversation, isViewOnly: isViewOnly, onSearch: onSearch }, conversation.conversationID))] }), _jsx("div", { className: "flex flex-col px-3 py-1.5", children: _jsx(MediaEntryCard, { onSelect: onSelectResource }) }), showActions && (_jsx(ThreadProfileActionRows, { conversation: conversation, displayName: displayName, showPersonRows: showPersonRows, isTargetActive: isTargetActive, isViewOnly: isViewOnly, canLeaveGroup: canLeaveGroup, onLeaveGroup: openLeaveGroup }, conversation.conversationID)), !showActions && canLeaveGroup && (_jsx("div", { className: "flex flex-col px-3 py-1.5", children: _jsx("div", { className: "overflow-hidden rounded-xl bg-white", children: _jsxs("button", { type: "button", "data-testid": "thread-profile-leave-group", className: "flex w-full cursor-pointer items-center gap-2 p-4 text-danger-400", onClick: openLeaveGroup, children: [_jsx(Icon, { icon: "logout-o", size: 24 }), _jsx("span", { className: "text-[16px] font-medium leading-[1.6]", children: t("thread_detail.leave_group.action") })] }) }) }))] }), _jsx(LeaveGroupConfirmModal, { open: isConfirmOpen, loading: isLeaving, isPublicGroup: isPublicGroup, onCancel: closeConfirm, onConfirm: confirmLeaveGroup }), _jsx(LeaveGroupBlockedModal, { open: isBlockedOpen, onClose: closeBlocked })] }));
|
|
27
37
|
};
|
|
28
38
|
export default ThreadProfilePanel;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface PinThreadLimitModalProps {
|
|
2
|
+
open: boolean;
|
|
3
|
+
onClose: () => void;
|
|
4
|
+
}
|
|
5
|
+
declare const PinThreadLimitModal: ({ open, onClose }: PinThreadLimitModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export default PinThreadLimitModal;
|
|
7
|
+
//# sourceMappingURL=PinThreadLimitModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PinThreadLimitModal.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/profile/PinThreadLimitModal.tsx"],"names":[],"mappings":"AAOA,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAGD,QAAA,MAAM,mBAAmB,GAAI,mBAAmB,wBAAwB,4CA6CvE,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Modal, Button } from "antd";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
const MODAL_WIDTH = 400;
|
|
6
|
+
// Same blocking-modal layout as LeaveGroupBlockedModal.
|
|
7
|
+
const PinThreadLimitModal = ({ open, onClose }) => {
|
|
8
|
+
const { t } = useTranslation("conversation-inbox");
|
|
9
|
+
return (_jsx(Modal, { "data-cp-name": "PinThreadLimitModal", open: open, onCancel: onClose, footer: null, closable: false, centered: true, width: MODAL_WIDTH, styles: {
|
|
10
|
+
content: { padding: 0, overflow: "hidden", borderRadius: 16 },
|
|
11
|
+
body: { padding: 0 },
|
|
12
|
+
}, children: _jsxs("div", { role: "alertdialog", "aria-label": t("thread_detail.profile.pin_limit_title"), className: "flex flex-col bg-white", children: [_jsxs("div", { className: "flex flex-col gap-3 p-4 text-center text-gray-900", children: [_jsx("p", { className: "text-[18px] font-bold leading-[1.6]", children: t("thread_detail.profile.pin_limit_title") }), _jsx("p", { className: "text-[16px] leading-[1.6] tracking-[0.16px]", children: t("thread_detail.profile.pin_limit_desc") })] }), _jsx("div", { className: "border-t border-gray-25" }), _jsx("div", { className: "p-4", children: _jsx(Button, { "data-testid": "pin-thread-limit-confirm", type: "primary", className: "h-12 w-full !rounded-lg !border-[var(--dc-color-primary)] !bg-[var(--dc-color-primary)] !text-[16px] !font-medium !text-white hover:!border-[var(--dc-color-primary-hover)] hover:!bg-[var(--dc-color-primary-hover)]", onClick: onClose, children: t("thread_detail.profile.pin_limit_confirm") }) })] }) }));
|
|
13
|
+
};
|
|
14
|
+
export default PinThreadLimitModal;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ConversationItem } from "@droppii-org/wasm-client-sdk";
|
|
2
|
+
export interface ThreadProfileActionRowsProps {
|
|
3
|
+
conversation: ConversationItem;
|
|
4
|
+
displayName: string;
|
|
5
|
+
/** Orders / create group / add to group: 1-1 threads with a person. */
|
|
6
|
+
showPersonRows: boolean;
|
|
7
|
+
isTargetActive: boolean;
|
|
8
|
+
/** A non-member viewing a public group: no pin, delete or leave. */
|
|
9
|
+
isViewOnly: boolean;
|
|
10
|
+
canLeaveGroup: boolean;
|
|
11
|
+
onLeaveGroup: () => void;
|
|
12
|
+
}
|
|
13
|
+
declare const ThreadProfileActionRows: ({ conversation, displayName, showPersonRows, isTargetActive, isViewOnly, canLeaveGroup, onLeaveGroup, }: ThreadProfileActionRowsProps) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export default ThreadProfileActionRows;
|
|
15
|
+
//# sourceMappingURL=ThreadProfileActionRows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadProfileActionRows.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/profile/ThreadProfileActionRows.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAiDrE,MAAM,WAAW,4BAA4B;IAC3C,YAAY,EAAE,gBAAgB,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,uEAAuE;IACvE,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;IACxB,oEAAoE;IACpE,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B;AAID,QAAA,MAAM,uBAAuB,GAAI,yGAQ9B,4BAA4B,4CAqE9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
import { Icon } from "../../../components/icon";
|
|
6
|
+
import { usePinConversation } from "../../../hooks/conversation/usePinConversation";
|
|
7
|
+
import PinThreadLimitModal from "./PinThreadLimitModal";
|
|
8
|
+
const ProfileActionRow = ({ icon, label, testId, danger, chevron, onClick, }) => (_jsx("div", { className: "group/row px-3", children: _jsxs("button", { type: "button", "data-testid": testId, className: clsx("flex w-full cursor-pointer items-center gap-3 border-b border-gray-25 py-3 text-left group-last/row:border-b-0", danger ? "text-danger-400" : "text-gray-900"), onClick: onClick, children: [_jsx(Icon, { icon: icon, size: 24, className: "shrink-0" }), _jsx("span", { className: "min-w-0 flex-1 truncate text-[16px] font-medium leading-[1.6]", children: label }), chevron && (_jsx(Icon, { icon: "angle-right-o", size: 20, className: "shrink-0 text-gray-400" }))] }) }));
|
|
9
|
+
const Card = ({ children }) => (_jsx("div", { className: "flex flex-col px-3 py-1.5", children: _jsx("div", { className: "overflow-hidden rounded-xl bg-white", children: children }) }));
|
|
10
|
+
// Orders, create group, add to group and delete history are UI-only until
|
|
11
|
+
// their own tickets land (spec: "UI ready requirement").
|
|
12
|
+
const ThreadProfileActionRows = ({ conversation, displayName, showPersonRows, isTargetActive, isViewOnly, canLeaveGroup, onLeaveGroup, }) => {
|
|
13
|
+
const { t } = useTranslation("conversation-inbox");
|
|
14
|
+
const { togglePin, isLimitOpen, closeLimit } = usePinConversation();
|
|
15
|
+
const isPinned = !!conversation.isPinned;
|
|
16
|
+
const showGroupRows = showPersonRows && isTargetActive;
|
|
17
|
+
const canEditThread = !isViewOnly;
|
|
18
|
+
return (_jsxs(_Fragment, { children: [(showPersonRows || canEditThread) && (_jsxs(Card, { children: [showPersonRows && (_jsx(ProfileActionRow, { icon: "receipt-o", label: t("thread_detail.profile.orders", { name: displayName }), testId: "thread-profile-orders", chevron: true })), showGroupRows && (_jsx(ProfileActionRow, { icon: "user-three-o", label: t("thread_detail.profile.create_group", { name: displayName }), testId: "thread-profile-create-group", chevron: true })), showGroupRows && (_jsx(ProfileActionRow, { icon: "user-add-o", label: t("thread_detail.profile.add_to_group"), testId: "thread-profile-add-to-group", chevron: true })), canEditThread && (_jsx(ProfileActionRow, { icon: isPinned ? "thumbtack-off-o" : "thumbtack-o", label: t(isPinned ? "thread_detail.profile.unpin" : "thread_detail.profile.pin"), testId: "thread-profile-pin", onClick: () => togglePin(conversation) }))] })), (canLeaveGroup || canEditThread) && (_jsxs(Card, { children: [canLeaveGroup && (_jsx(ProfileActionRow, { icon: "logout-o", label: t("thread_detail.leave_group.action"), testId: "thread-profile-leave-group", danger: true, onClick: onLeaveGroup })), canEditThread && (_jsx(ProfileActionRow, { icon: "trash-alt-o", label: t("thread_detail.profile.delete_history"), testId: "thread-profile-delete-history", danger: true }))] })), _jsx(PinThreadLimitModal, { open: isLimitOpen, onClose: closeLimit })] }));
|
|
19
|
+
};
|
|
20
|
+
export default ThreadProfileActionRows;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ConversationItem } from "@droppii-org/wasm-client-sdk";
|
|
2
|
+
interface ThreadProfileQuickActionsProps {
|
|
3
|
+
conversation: ConversationItem;
|
|
4
|
+
/** A non-member viewing a public group: no search (BE only serves members) and no mute. */
|
|
5
|
+
isViewOnly: boolean;
|
|
6
|
+
/** Opens search in this thread; without it the entry stays UI-only. */
|
|
7
|
+
onSearch?: () => void;
|
|
8
|
+
}
|
|
9
|
+
declare const ThreadProfileQuickActions: ({ conversation, isViewOnly, onSearch, }: ThreadProfileQuickActionsProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
+
export default ThreadProfileQuickActions;
|
|
11
|
+
//# sourceMappingURL=ThreadProfileQuickActions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadProfileQuickActions.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/profile/ThreadProfileQuickActions.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AA6CrE,UAAU,8BAA8B;IACtC,YAAY,EAAE,gBAAgB,CAAC;IAC/B,2FAA2F;IAC3F,UAAU,EAAE,OAAO,CAAC;IACpB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,QAAA,MAAM,yBAAyB,GAAI,yCAIhC,8BAA8B,mDAkDhC,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import clsx from "clsx";
|
|
5
|
+
import { useTranslation } from "react-i18next";
|
|
6
|
+
import { Icon } from "../../../components/icon";
|
|
7
|
+
import MuteConversationConfirmModal from "../../../components/conversation-inbox/MuteConversationConfirmModal";
|
|
8
|
+
import { isConversationMuted, useMuteConversation, } from "../../../hooks/session/useMuteConversation";
|
|
9
|
+
const QuickAction = ({ icon, label, active, testId, onClick, }) => (_jsxs("button", { type: "button", "data-testid": testId, className: "flex w-[104px] cursor-pointer flex-col items-center gap-1 px-3 py-2", onClick: onClick, children: [_jsx("span", { className: clsx("flex h-10 w-10 items-center justify-center rounded-full", active
|
|
10
|
+
? "bg-[var(--dc-color-primary)] text-white"
|
|
11
|
+
: "bg-gray-25 text-gray-900"), children: _jsx(Icon, { icon: icon, size: 18 }) }), _jsx("span", { className: "whitespace-nowrap text-center text-[13px] font-medium leading-[1.6] text-gray-900", children: label })] }));
|
|
12
|
+
const ThreadProfileQuickActions = ({ conversation, isViewOnly, onSearch, }) => {
|
|
13
|
+
const { t } = useTranslation("conversation-inbox");
|
|
14
|
+
const { muteConversation, unmuteConversation, isPending } = useMuteConversation();
|
|
15
|
+
const [isConfirmOpen, setIsConfirmOpen] = useState(false);
|
|
16
|
+
const isMuted = isConversationMuted(conversation.recvMsgOpt);
|
|
17
|
+
const handleMuteClick = () => {
|
|
18
|
+
if (isPending)
|
|
19
|
+
return;
|
|
20
|
+
if (isMuted) {
|
|
21
|
+
unmuteConversation(conversation.conversationID);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
setIsConfirmOpen(true);
|
|
25
|
+
};
|
|
26
|
+
const handleConfirmMute = () => {
|
|
27
|
+
setIsConfirmOpen(false);
|
|
28
|
+
muteConversation(conversation.conversationID);
|
|
29
|
+
};
|
|
30
|
+
if (isViewOnly)
|
|
31
|
+
return null;
|
|
32
|
+
return (_jsxs("div", { className: "flex items-center justify-center gap-2", children: [_jsx(QuickAction, { icon: "search-o", label: t("thread_detail.profile.search"), testId: "thread-profile-search", onClick: onSearch }), _jsx(QuickAction, { icon: isMuted ? "bell-b" : "bell-off-o", label: t(isMuted
|
|
33
|
+
? "thread_card.mute.unmute_action"
|
|
34
|
+
: "thread_card.mute.mute_action"), active: isMuted, testId: "thread-profile-mute", onClick: handleMuteClick }), _jsx(MuteConversationConfirmModal, { open: isConfirmOpen, loading: isPending, onCancel: () => setIsConfirmOpen(false), onConfirm: handleConfirmMute })] }));
|
|
35
|
+
};
|
|
36
|
+
export default ThreadProfileQuickActions;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
import { type InputRef } from "antd";
|
|
3
|
+
import { type ConversationItem } from "@droppii-org/wasm-client-sdk";
|
|
4
|
+
export interface ThreadSearchContentProps {
|
|
5
|
+
conversation: ConversationItem;
|
|
6
|
+
inputRef: RefObject<InputRef>;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
/** Host toast for a hit that was revoked meanwhile; the SDK toast shows otherwise. */
|
|
9
|
+
onSearchMessageRevoked?: () => void;
|
|
10
|
+
}
|
|
11
|
+
declare const ThreadSearchContent: ({ conversation, inputRef, onClose, onSearchMessageRevoked, }: ThreadSearchContentProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export default ThreadSearchContent;
|
|
13
|
+
//# sourceMappingURL=ThreadSearchContent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadSearchContent.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/thread-search/ThreadSearchContent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,EAAwC,KAAK,QAAQ,EAAE,MAAM,MAAM,CAAC;AAI3E,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,8BAA8B,CAAC;AAYtC,MAAM,WAAW,wBAAwB;IACvC,YAAY,EAAE,gBAAgB,CAAC;IAC/B,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,sFAAsF;IACtF,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAGD,QAAA,MAAM,mBAAmB,GAAI,8DAK1B,wBAAwB,4CAoJ1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Input, Spin, message as toastMessage } from "antd";
|
|
5
|
+
import { useDebounce } from "ahooks";
|
|
6
|
+
import InfiniteScroll from "react-infinite-scroll-component";
|
|
7
|
+
import { useTranslation } from "react-i18next";
|
|
8
|
+
import { MessageType, } from "@droppii-org/wasm-client-sdk";
|
|
9
|
+
import { Icon } from "../../../components/icon";
|
|
10
|
+
import ContactSearchStateMessage from "../../../components/conversation-inbox/contact-search/ContactSearchStateMessage";
|
|
11
|
+
import { useSearchThreadMessages } from "../../../hooks/search/useSearchThreadMessages";
|
|
12
|
+
import useAuthStore from "../../../store/auth";
|
|
13
|
+
import useConversationStore from "../../../store/conversation";
|
|
14
|
+
import { emit } from "../../../utils/events";
|
|
15
|
+
import ThreadSearchResultItem from "./ThreadSearchResultItem";
|
|
16
|
+
import { THREAD_SEARCH_DEBOUNCE_MS } from "./utils";
|
|
17
|
+
const SCROLL_TARGET_ID = "thread-search-results";
|
|
18
|
+
// Lives inside the Drawer, which destroys it on close: every open starts from an empty keyword.
|
|
19
|
+
const ThreadSearchContent = ({ conversation, inputRef, onClose, onSearchMessageRevoked, }) => {
|
|
20
|
+
const { t } = useTranslation("conversation-inbox");
|
|
21
|
+
const { t: tCommon } = useTranslation();
|
|
22
|
+
const selfUserID = useAuthStore((state) => state.userID);
|
|
23
|
+
const [keyword, setKeyword] = useState("");
|
|
24
|
+
const debouncedKeyword = useDebounce(keyword, {
|
|
25
|
+
wait: THREAD_SEARCH_DEBOUNCE_MS,
|
|
26
|
+
});
|
|
27
|
+
const typedTerm = keyword.trim();
|
|
28
|
+
const term = typedTerm ? debouncedKeyword.trim() : "";
|
|
29
|
+
const { results, isLoading, isError, hasNextPage, isFetchNextPageError, fetchNextPage, } = useSearchThreadMessages(conversation.conversationID, term);
|
|
30
|
+
const handleSelect = (hit) => {
|
|
31
|
+
if (hit.isRevoked || hit.contentType === MessageType.RevokeMessage) {
|
|
32
|
+
if (onSearchMessageRevoked)
|
|
33
|
+
onSearchMessageRevoked();
|
|
34
|
+
else
|
|
35
|
+
toastMessage.info(tCommon("message_revoked_or_deleted"));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Same jump as the pinned list, with the longer search highlight.
|
|
39
|
+
const store = useConversationStore.getState();
|
|
40
|
+
store.setHeldHighlightClientMsgID(hit.clientMsgID);
|
|
41
|
+
store.setSearchClientMsgID(hit.clientMsgID);
|
|
42
|
+
emit("CHAT_LIST_SCROLL_TO_MESSAGE", hit.clientMsgID);
|
|
43
|
+
onClose();
|
|
44
|
+
};
|
|
45
|
+
const renderBody = () => {
|
|
46
|
+
if (!typedTerm || !term) {
|
|
47
|
+
return (_jsx("div", { role: "status", className: "flex flex-1 flex-col", children: _jsx(ContactSearchStateMessage, { testId: "thread-search-initial", children: t("thread_detail.search.initial") }) }));
|
|
48
|
+
}
|
|
49
|
+
if (isLoading) {
|
|
50
|
+
return (_jsx("div", { "data-testid": "thread-search-loading", className: "flex justify-center py-8", children: _jsx(Spin, {}) }));
|
|
51
|
+
}
|
|
52
|
+
if (results.length === 0) {
|
|
53
|
+
return (_jsx("div", { role: "status", className: "flex flex-1 flex-col", children: _jsx(ContactSearchStateMessage, { testId: "thread-search-empty", children: isError ? (t("thread_detail.search.failed")) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "block", children: t("thread_detail.search.no_result_title") }), _jsx("span", { className: "block", children: t("thread_detail.search.no_result_hint") })] })) }) }));
|
|
54
|
+
}
|
|
55
|
+
return (_jsx("div", { id: SCROLL_TARGET_ID, className: "min-h-0 flex-1 overflow-y-auto", children: _jsx(InfiniteScroll, { dataLength: results.length, next: fetchNextPage,
|
|
56
|
+
// A failed page would otherwise leave the loader spinning for good.
|
|
57
|
+
hasMore: !!hasNextPage && !isFetchNextPageError, loader: _jsx("div", { className: "flex justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: SCROLL_TARGET_ID, children: results.map((item) => {
|
|
58
|
+
var _a;
|
|
59
|
+
return (_jsx(ThreadSearchResultItem, { message: Object.assign(Object.assign({}, item.chatLog), {
|
|
60
|
+
// The app endpoint reports it on chatLog, the CRM one on the item.
|
|
61
|
+
isRevoked: (_a = item.chatLog.isRevoked) !== null && _a !== void 0 ? _a : item.isRevoked }), conversation: conversation, selfUserID: selfUserID, searchTerm: term, onSelect: handleSelect }, item.chatLog.clientMsgID));
|
|
62
|
+
}) }) }));
|
|
63
|
+
};
|
|
64
|
+
return (_jsxs("div", { className: "flex h-full flex-col bg-white", children: [_jsxs("div", { className: "flex shrink-0 items-center gap-2 border-b border-gray-25 p-2", children: [_jsx("button", { type: "button", "data-testid": "thread-search-back", "aria-label": t("thread_detail.search.back"), className: "flex shrink-0 cursor-pointer items-center justify-center p-2 text-[var(--dc-color-nav-icon)]", onClick: onClose, children: _jsx(Icon, { icon: "arrow-left-o", size: 24 }) }), _jsx(Input, { ref: inputRef, allowClear: true, autoFocus: true, value: keyword, "aria-label": t("thread_detail.search.placeholder"), "data-testid": "thread-search-input", placeholder: t("thread_detail.search.placeholder"), prefix: _jsx("span", { className: "flex h-10 w-10 items-center justify-center", children: _jsx(Icon, { icon: "search-o", size: 18 }) }), className: "!h-10 !flex-1 !rounded-lg !border-none !bg-gray-25 !p-0 !shadow-none", classNames: {
|
|
65
|
+
prefix: "!m-0 text-gray-600",
|
|
66
|
+
input: "!bg-transparent !px-0 !text-[14px] !leading-[1.6] !text-gray-900",
|
|
67
|
+
suffix: "!mr-4",
|
|
68
|
+
}, onChange: (event) => setKeyword(event.target.value) })] }), renderBody()] }));
|
|
69
|
+
};
|
|
70
|
+
export default ThreadSearchContent;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ConversationItem } from "@droppii-org/wasm-client-sdk";
|
|
2
|
+
interface ThreadSearchPanelProps {
|
|
3
|
+
open: boolean;
|
|
4
|
+
conversation: ConversationItem;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
/** Host toast for a hit that was revoked meanwhile; the SDK toast shows otherwise. */
|
|
7
|
+
onSearchMessageRevoked?: () => void;
|
|
8
|
+
}
|
|
9
|
+
declare const ThreadSearchPanel: ({ open, conversation, onClose, onSearchMessageRevoked, }: ThreadSearchPanelProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export default ThreadSearchPanel;
|
|
11
|
+
//# sourceMappingURL=ThreadSearchPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadSearchPanel.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/thread-search/ThreadSearchPanel.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGrE,UAAU,sBAAsB;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,gBAAgB,CAAC;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,sFAAsF;IACtF,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,iBAAiB,GAAI,0DAKxB,sBAAsB,4CAyBxB,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useRef } from "react";
|
|
4
|
+
import { Drawer } from "antd";
|
|
5
|
+
import ThreadSearchContent from "./ThreadSearchContent";
|
|
6
|
+
const ThreadSearchPanel = ({ open, conversation, onClose, onSearchMessageRevoked, }) => {
|
|
7
|
+
const inputRef = useRef(null);
|
|
8
|
+
return (_jsx(Drawer, { open: open, onClose: onClose, placement: "right", closeIcon: false, width: "100%", "data-cp-name": "ThreadSearchPanel", styles: { body: { padding: 0 } }, getContainer: false, destroyOnHidden: true,
|
|
9
|
+
// rc-drawer focuses its own panel after mount, which beats autoFocus.
|
|
10
|
+
afterOpenChange: (visible) => { var _a; return visible && ((_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus()); }, children: _jsx(ThreadSearchContent, { conversation: conversation, inputRef: inputRef, onClose: onClose, onSearchMessageRevoked: onSearchMessageRevoked }) }));
|
|
11
|
+
};
|
|
12
|
+
export default ThreadSearchPanel;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ConversationItem, MessageItem } from "@droppii-org/wasm-client-sdk";
|
|
2
|
+
interface ThreadSearchResultItemProps {
|
|
3
|
+
message: MessageItem;
|
|
4
|
+
conversation: ConversationItem;
|
|
5
|
+
selfUserID: string;
|
|
6
|
+
searchTerm: string;
|
|
7
|
+
onSelect: (message: MessageItem) => void;
|
|
8
|
+
}
|
|
9
|
+
declare const ThreadSearchResultItem: ({ message, conversation, selfUserID, searchTerm, onSelect, }: ThreadSearchResultItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export default ThreadSearchResultItem;
|
|
11
|
+
//# sourceMappingURL=ThreadSearchResultItem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadSearchResultItem.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/thread-search/ThreadSearchResultItem.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACZ,MAAM,8BAA8B,CAAC;AAQtC,UAAU,2BAA2B;IACnC,OAAO,EAAE,WAAW,CAAC;IACrB,YAAY,EAAE,gBAAgB,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CAC1C;AAED,QAAA,MAAM,sBAAsB,GAAI,8DAM7B,2BAA2B,4CA+D7B,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Avatar } from "antd";
|
|
4
|
+
import { useTranslation } from "react-i18next";
|
|
5
|
+
import { Icon } from "../../../components/icon";
|
|
6
|
+
import { PeerType } from "../../../types/conversation";
|
|
7
|
+
import { formatTimestamp, splitHighlight } from "../../../utils/common";
|
|
8
|
+
import { getSearchHitText } from "./utils";
|
|
9
|
+
const AVATAR_SIZE = 40;
|
|
10
|
+
const ThreadSearchResultItem = ({ message, conversation, selfUserID, searchTerm, onSelect, }) => {
|
|
11
|
+
const { t } = useTranslation("conversation-inbox");
|
|
12
|
+
const isOwn = !!selfUserID && message.sendID === selfUserID;
|
|
13
|
+
// Bot threads are answered by a system account; show the bot like biz-mobile does.
|
|
14
|
+
const isBotSender = !isOwn && conversation.peerType === PeerType.BOT;
|
|
15
|
+
const name = isOwn
|
|
16
|
+
? t("thread_detail.search.you")
|
|
17
|
+
: (isBotSender ? conversation.showName : message.senderNickname) || "";
|
|
18
|
+
const avatarUrl = isBotSender ? conversation.faceURL : message.senderFaceUrl;
|
|
19
|
+
const time = formatTimestamp(message.sendTime, { hasTime: true });
|
|
20
|
+
const text = getSearchHitText(message);
|
|
21
|
+
const parts = splitHighlight(text, searchTerm.trim());
|
|
22
|
+
return (_jsx("div", { className: "group/row px-3", children: _jsxs("button", { type: "button", "data-testid": "thread-search-result", className: "flex w-full cursor-pointer items-center gap-4 border-b border-gray-25 py-2 text-left group-last/row:border-b-0", onClick: () => onSelect(message), children: [_jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-2", children: [_jsx(Avatar, { size: AVATAR_SIZE, src: avatarUrl || undefined, alt: name, className: "shrink-0 uppercase", children: name.charAt(0) || "A" }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("span", { className: "truncate text-[16px] font-medium leading-[1.6] text-black", children: name }), _jsxs("span", { className: "flex min-w-0 text-[14px] leading-[1.6] text-gray-600", children: [_jsx("span", { "data-testid": "thread-search-result-preview", className: "min-w-0 truncate", children: parts ? (_jsxs(_Fragment, { children: [parts.before, _jsx("span", { className: "text-[var(--dc-color-primary)]", children: parts.match }), parts.after] })) : (text) }), _jsx("span", { className: "shrink-0 whitespace-pre", children: ` • ${time}` })] })] })] }), _jsx(Icon, { icon: "angle-right-o", size: 24, className: "shrink-0 text-gray-600" })] }) }));
|
|
23
|
+
};
|
|
24
|
+
export default ThreadSearchResultItem;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MessageItem } from "@droppii-org/wasm-client-sdk";
|
|
2
|
+
export declare const THREAD_SEARCH_DEBOUNCE_MS = 500;
|
|
3
|
+
/**
|
|
4
|
+
* Visible text of a search hit. Text and link messages keep it in `content`,
|
|
5
|
+
* quote and mention messages in `text`; line breaks collapse for the one-line preview.
|
|
6
|
+
*/
|
|
7
|
+
export declare const getSearchHitText: (message: Pick<MessageItem, "content">) => string;
|
|
8
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/thread-search/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAEhE,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,WASrE,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const THREAD_SEARCH_DEBOUNCE_MS = 500;
|
|
2
|
+
/**
|
|
3
|
+
* Visible text of a search hit. Text and link messages keep it in `content`,
|
|
4
|
+
* quote and mention messages in `text`; line breaks collapse for the one-line preview.
|
|
5
|
+
*/
|
|
6
|
+
export const getSearchHitText = (message) => {
|
|
7
|
+
var _a, _b;
|
|
8
|
+
let text = "";
|
|
9
|
+
try {
|
|
10
|
+
const parsed = JSON.parse(message.content || "{}");
|
|
11
|
+
text = (_b = (_a = parsed === null || parsed === void 0 ? void 0 : parsed.content) !== null && _a !== void 0 ? _a : parsed === null || parsed === void 0 ? void 0 : parsed.text) !== null && _b !== void 0 ? _b : "";
|
|
12
|
+
}
|
|
13
|
+
catch (_c) {
|
|
14
|
+
text = typeof message.content === "string" ? message.content : "";
|
|
15
|
+
}
|
|
16
|
+
return String(text).replace(/\s+/g, " ").trim();
|
|
17
|
+
};
|
|
@@ -2,7 +2,9 @@ import type { ConversationListItem } from "../../types/conversation";
|
|
|
2
2
|
export interface ConversationInboxItemProps {
|
|
3
3
|
item: ConversationListItem;
|
|
4
4
|
onClick: (item: ConversationListItem) => void;
|
|
5
|
+
/** Ghim / Bỏ ghim in the swipe actions plus a right-click menu. Defaults to false. */
|
|
6
|
+
showPinThread?: boolean;
|
|
5
7
|
}
|
|
6
|
-
declare const ConversationInboxItem: ({ item, onClick }: ConversationInboxItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
declare const ConversationInboxItem: ({ item, onClick, showPinThread, }: ConversationInboxItemProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
9
|
export default ConversationInboxItem;
|
|
8
10
|
//# sourceMappingURL=ConversationInboxItem.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationInboxItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/ConversationInboxItem.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"ConversationInboxItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/ConversationInboxItem.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAkBjE,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,OAAO,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC9C,sFAAsF;IACtF,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAQD,QAAA,MAAM,qBAAqB,GAAI,mCAI5B,0BAA0B,4CAwG5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -12,19 +12,17 @@ import { useIsJoinedGroup } from "../../hooks/session/useIsJoinedGroup";
|
|
|
12
12
|
import { isConversationMuted } from "../../hooks/session/useMuteConversation";
|
|
13
13
|
import ThreadCard from "../../components/conversation/ThreadCard";
|
|
14
14
|
import MentionIndicatorIcon from "../../components/conversation/MentionIndicatorIcon";
|
|
15
|
-
import SwipeableRow from "../../components/conversation/SwipeableRow";
|
|
16
|
-
import { SWIPE_ACTION_WIDTH } from "../../components/conversation/SwipeActionButton";
|
|
17
15
|
import { Icon } from "../../components/icon";
|
|
18
16
|
import ConversationPeerAvatar from "./ConversationPeerAvatar";
|
|
19
17
|
import ConversationInboxTitle from "./ConversationInboxTitle";
|
|
20
|
-
import
|
|
18
|
+
import ConversationThreadActions from "./ConversationThreadActions";
|
|
21
19
|
const formatLatestMessageTime = (sendTime) => {
|
|
22
20
|
if (!sendTime)
|
|
23
21
|
return "";
|
|
24
22
|
const isToday = dayjs(sendTime).isSame(dayjs(), "day");
|
|
25
23
|
return formatTimestamp(sendTime, { hasTime: isToday });
|
|
26
24
|
};
|
|
27
|
-
const ConversationInboxItem = ({ item, onClick }) => {
|
|
25
|
+
const ConversationInboxItem = ({ item, onClick, showPinThread = false, }) => {
|
|
28
26
|
var _a;
|
|
29
27
|
const { t } = useTranslation("conversation-inbox");
|
|
30
28
|
const { t: tCommon } = useTranslation("common");
|
|
@@ -57,10 +55,10 @@ const ConversationInboxItem = ({ item, onClick }) => {
|
|
|
57
55
|
const isMuted = isConversationMuted(item.recvMsgOpt);
|
|
58
56
|
const { isJoined } = useIsJoinedGroup(item.groupID);
|
|
59
57
|
const hasLostGroupAccess = Boolean(item.groupID) && isJoined !== true;
|
|
60
|
-
const threadCard = (_jsx(ThreadCard, { testId: "conversation-inbox-thread-card", onClick: () => onClick(item), unreadCount: unreadCount, time: latestMessageTime, preview: latestMessagePreview, mentionIndicator: _jsx(MentionIndicatorIcon, { groupAtType: item.groupAtType }), muteIndicator: isMuted ? (_jsx(Icon, { icon: "bell-off-b", size: 16, "aria-label": t("thread_card.mute.muted_icon_label"), className: "shrink-0 text-gray-400" })) : null, avatar: _jsx(ConversationPeerAvatar, { peerType: item.peerType, displayName: displayName, avatarUrl: avatarUrl, badgeLabel: badgeLabel }), title: _jsx(ConversationInboxTitle, { peerType: item.peerType, displayName: displayName, hasUnread: unreadCount > 0 }) }));
|
|
58
|
+
const threadCard = (_jsx(ThreadCard, { testId: "conversation-inbox-thread-card", onClick: () => onClick(item), unreadCount: unreadCount, time: latestMessageTime, preview: latestMessagePreview, mentionIndicator: _jsx(MentionIndicatorIcon, { groupAtType: item.groupAtType }), pinIndicator: item.isPinned ? (_jsx(Icon, { icon: "thumbtack-b", size: 16, "data-testid": "conversation-inbox-pinned-icon", "aria-label": t("thread_card.pin.pinned_icon_label"), className: "shrink-0 text-[var(--dc-color-primary)]" })) : null, muteIndicator: isMuted ? (_jsx(Icon, { icon: "bell-off-b", size: 16, "aria-label": t("thread_card.mute.muted_icon_label"), className: "shrink-0 text-gray-400" })) : null, avatar: _jsx(ConversationPeerAvatar, { peerType: item.peerType, displayName: displayName, avatarUrl: avatarUrl, badgeLabel: badgeLabel }), title: _jsx(ConversationInboxTitle, { peerType: item.peerType, displayName: displayName, hasUnread: unreadCount > 0 }) }));
|
|
61
59
|
if (hasLostGroupAccess) {
|
|
62
60
|
return threadCard;
|
|
63
61
|
}
|
|
64
|
-
return (_jsx(
|
|
62
|
+
return (_jsx(ConversationThreadActions, { conversation: item, isMuted: isMuted, showPin: showPinThread, children: threadCard }));
|
|
65
63
|
};
|
|
66
64
|
export default ConversationInboxItem;
|
|
@@ -6,7 +6,9 @@ export interface ConversationInboxListProps {
|
|
|
6
6
|
hasNextPage: boolean;
|
|
7
7
|
onLoadMore: () => void;
|
|
8
8
|
onSelectThread?: (item: ConversationListItem) => void;
|
|
9
|
+
/** See ConversationInboxItemProps.showPinThread. */
|
|
10
|
+
showPinThread?: boolean;
|
|
9
11
|
}
|
|
10
|
-
declare const ConversationInboxList: ({ items, isLoading, isFetchingNextPage, hasNextPage, onLoadMore, onSelectThread, }: ConversationInboxListProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
declare const ConversationInboxList: ({ items, isLoading, isFetchingNextPage, hasNextPage, onLoadMore, onSelectThread, showPinThread, }: ConversationInboxListProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
13
|
export default ConversationInboxList;
|
|
12
14
|
//# sourceMappingURL=ConversationInboxList.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationInboxList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/ConversationInboxList.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAYjE,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,oBAAoB,EAAE,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ConversationInboxList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/ConversationInboxList.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAYjE,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,oBAAoB,EAAE,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACtD,oDAAoD;IACpD,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAYD,QAAA,MAAM,qBAAqB,GAAI,mGAQ5B,0BAA0B,4CA+F5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|