@droppii-org/chat-sdk 0.3.6 → 0.3.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/common/ConfirmModal.d.ts +18 -0
- package/dist/components/common/ConfirmModal.d.ts.map +1 -0
- package/dist/components/common/ConfirmModal.js +15 -0
- package/dist/components/common/InfoModal.d.ts +11 -0
- package/dist/components/common/InfoModal.d.ts.map +1 -0
- package/dist/components/common/InfoModal.js +13 -0
- package/dist/components/compose/ComposeNewMessageModal.d.ts.map +1 -1
- package/dist/components/compose/ComposeNewMessageModal.js +4 -6
- package/dist/components/conversation/ConversationByGroupItem.d.ts.map +1 -1
- package/dist/components/conversation/ConversationByGroupItem.js +3 -7
- package/dist/components/conversation/ConversationBySessionItem.d.ts.map +1 -1
- package/dist/components/conversation/ConversationBySessionItem.js +3 -7
- package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
- package/dist/components/conversation/DeskConversationList.js +20 -14
- package/dist/components/conversation-inbox/ConversationInboxList.d.ts.map +1 -1
- package/dist/components/conversation-inbox/ConversationInboxList.js +4 -6
- package/dist/components/message/GroupMembersDrawer.d.ts.map +1 -1
- package/dist/components/message/GroupMembersDrawer.js +8 -8
- package/dist/components/message/MessageList.d.ts.map +1 -1
- package/dist/components/message/MessageList.js +17 -3
- package/dist/components/message/item/MessageBubble.d.ts +3 -2
- package/dist/components/message/item/MessageBubble.d.ts.map +1 -1
- package/dist/components/message/item/MessageBubble.js +8 -2
- package/dist/components/message/item/index.d.ts.map +1 -1
- package/dist/components/message/item/index.js +23 -6
- package/dist/components/thread/GroupThreadInfo.d.ts.map +1 -1
- package/dist/components/thread/GroupThreadInfo.js +43 -14
- package/dist/components/thread/SingleThreadInfo.d.ts.map +1 -1
- package/dist/components/thread/SingleThreadInfo.js +3 -2
- package/dist/context/ChatContext.d.ts +1 -1
- package/dist/context/ChatContext.d.ts.map +1 -1
- package/dist/context/ChatContext.js +2 -1
- package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
- package/dist/hooks/global/useGlobalEvent.js +29 -4
- package/dist/hooks/group/useCreateGroup.js +5 -5
- package/dist/hooks/group/useDismissGroup.d.ts.map +1 -1
- package/dist/hooks/group/useDismissGroup.js +18 -0
- package/dist/hooks/session/useConversationSessionState.d.ts.map +1 -1
- package/dist/hooks/session/useConversationSessionState.js +1 -0
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +13 -2
- package/dist/locales/vi/common.json +14 -8
- package/dist/screens/conversation-detail/index.d.ts.map +1 -1
- package/dist/screens/conversation-detail/index.js +6 -7
- package/dist/store/conversation.d.ts.map +1 -1
- package/dist/store/conversation.js +26 -5
- package/dist/store/type.d.ts +5 -0
- package/dist/store/type.d.ts.map +1 -1
- package/dist/styles/global.css +1 -1
- package/dist/types/chat.d.ts +2 -0
- package/dist/types/chat.d.ts.map +1 -1
- package/dist/utils/common.d.ts +1 -0
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/common.js +18 -0
- package/dist/utils/fileValidation.d.ts.map +1 -1
- package/dist/utils/fileValidation.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface ConfirmModalProps {
|
|
3
|
+
open: boolean;
|
|
4
|
+
title: ReactNode;
|
|
5
|
+
okText: ReactNode;
|
|
6
|
+
cancelText: ReactNode;
|
|
7
|
+
onOk: () => void;
|
|
8
|
+
onCancel: () => void;
|
|
9
|
+
okType?: "danger" | "primary";
|
|
10
|
+
confirmLoading?: boolean;
|
|
11
|
+
okButtonProps?: {
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
};
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
}
|
|
16
|
+
declare const ConfirmModal: ({ open, title, okText, cancelText, onOk, onCancel, okType, confirmLoading, okButtonProps, children, }: ConfirmModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export default ConfirmModal;
|
|
18
|
+
//# sourceMappingURL=ConfirmModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfirmModal.d.ts","sourceRoot":"","sources":["../../../src/components/common/ConfirmModal.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,UAAU,EAAE,SAAS,CAAC;IACtB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACvC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,QAAA,MAAM,YAAY,GAAI,uGAWnB,iBAAiB,4CAiCnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Modal } from "antd";
|
|
4
|
+
const ConfirmModal = ({ open, title, okText, cancelText, onOk, onCancel, okType = "primary", confirmLoading, okButtonProps, children, }) => {
|
|
5
|
+
return (_jsx(Modal, { centered: true, open: open, onOk: onOk, onCancel: onCancel, okText: okText, cancelText: cancelText, confirmLoading: confirmLoading, okButtonProps: Object.assign(Object.assign({}, okButtonProps), { className: okType === "danger"
|
|
6
|
+
? "!h-10 !rounded-lg !border-danger-400 !bg-danger-400 !text-white hover:!border-danger-300 hover:!bg-danger-300"
|
|
7
|
+
: "!h-10 !rounded-lg !border-primary-400 !bg-primary-400 !text-white hover:!border-primary-300 hover:!bg-primary-300" }), cancelButtonProps: {
|
|
8
|
+
className: "!h-10 !rounded-lg !border-gray-25 !bg-gray-25 !text-gray-900",
|
|
9
|
+
}, styles: {
|
|
10
|
+
header: { textAlign: "center", marginBottom: 0 },
|
|
11
|
+
footer: { marginTop: 16 },
|
|
12
|
+
body: { paddingTop: 4 },
|
|
13
|
+
}, classNames: { footer: "border-t border-gray-25 pt-4" }, title: _jsx("span", { className: "text-[18px] font-bold text-gray-900", children: title }), getContainer: false, forceRender: true, children: children }));
|
|
14
|
+
};
|
|
15
|
+
export default ConfirmModal;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export interface InfoModalProps {
|
|
3
|
+
open: boolean;
|
|
4
|
+
title: ReactNode;
|
|
5
|
+
okText: ReactNode;
|
|
6
|
+
onOk: () => void;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
declare const InfoModal: ({ open, title, okText, onOk, children }: InfoModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export default InfoModal;
|
|
11
|
+
//# sourceMappingURL=InfoModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InfoModal.d.ts","sourceRoot":"","sources":["../../../src/components/common/InfoModal.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,QAAA,MAAM,SAAS,GAAI,yCAAyC,cAAc,4CA0BzE,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Modal } from "antd";
|
|
4
|
+
const InfoModal = ({ open, title, okText, onOk, children }) => {
|
|
5
|
+
return (_jsx(Modal, { centered: true, open: open, onOk: onOk, onCancel: onOk, okText: okText, cancelButtonProps: { style: { display: "none" } }, okButtonProps: {
|
|
6
|
+
className: "!h-10 !w-full !rounded-lg !border-primary-400 !bg-primary-400 !text-white hover:!border-primary-300 hover:!bg-primary-300",
|
|
7
|
+
}, styles: {
|
|
8
|
+
header: { textAlign: "center", marginBottom: 0 },
|
|
9
|
+
footer: { marginTop: 16 },
|
|
10
|
+
body: { paddingTop: 4 },
|
|
11
|
+
}, classNames: { footer: "border-t border-gray-25 pt-4" }, title: _jsx("span", { className: "text-[18px] font-bold text-gray-900", children: title }), getContainer: false, forceRender: true, children: children }));
|
|
12
|
+
};
|
|
13
|
+
export default InfoModal;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComposeNewMessageModal.d.ts","sourceRoot":"","sources":["../../../src/components/compose/ComposeNewMessageModal.tsx"],"names":[],"mappings":"AAeA,UAAU,2BAA2B;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAID,QAAA,MAAM,sBAAsB,GAAI,oBAG7B,2BAA2B,
|
|
1
|
+
{"version":3,"file":"ComposeNewMessageModal.d.ts","sourceRoot":"","sources":["../../../src/components/compose/ComposeNewMessageModal.tsx"],"names":[],"mappings":"AAeA,UAAU,2BAA2B;IACnC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAID,QAAA,MAAM,sBAAsB,GAAI,oBAG7B,2BAA2B,4CAsI7B,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -3,7 +3,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useDebounce } from "ahooks";
|
|
4
4
|
import { Avatar, Empty, Input, Modal, Spin } from "antd";
|
|
5
5
|
import { useState } from "react";
|
|
6
|
-
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
7
6
|
import { useTranslation } from "react-i18next";
|
|
8
7
|
import { SessionType } from "@droppii-org/wasm-client-sdk";
|
|
9
8
|
import { Icon } from "../../components/icon";
|
|
@@ -11,6 +10,7 @@ import { useEligibleAccounts } from "../../hooks/group/useEligibleAccounts";
|
|
|
11
10
|
import { DChatSDK } from "../../constants/sdk";
|
|
12
11
|
import useConversationStore from "../../store/conversation";
|
|
13
12
|
import CreateGroupForm from "../../components/group/CreateGroupForm";
|
|
13
|
+
import { useChatContext } from "../../context/ChatContext";
|
|
14
14
|
const ComposeNewMessageModal = ({ open, onClose, }) => {
|
|
15
15
|
const { t } = useTranslation("conversation-inbox");
|
|
16
16
|
const [step, setStep] = useState("compose");
|
|
@@ -18,9 +18,7 @@ const ComposeNewMessageModal = ({ open, onClose, }) => {
|
|
|
18
18
|
const [openingUserID, setOpeningUserID] = useState(null);
|
|
19
19
|
const debouncedSearch = useDebounce(search, { wait: 300 });
|
|
20
20
|
const { accounts, isLoading } = useEligibleAccounts(debouncedSearch, open);
|
|
21
|
-
const
|
|
22
|
-
const pathname = usePathname();
|
|
23
|
-
const searchParams = useSearchParams();
|
|
21
|
+
const { onNavigate } = useChatContext();
|
|
24
22
|
const setConversationData = useConversationStore((state) => state.setConversationData);
|
|
25
23
|
const setSelectedConversationId = useConversationStore((state) => state.setSelectedConversationId);
|
|
26
24
|
const handleClose = () => {
|
|
@@ -44,12 +42,12 @@ const ComposeNewMessageModal = ({ open, onClose, }) => {
|
|
|
44
42
|
});
|
|
45
43
|
setConversationData(conversation);
|
|
46
44
|
setSelectedConversationId(conversation.conversationID);
|
|
47
|
-
const newSearchParams = new URLSearchParams(
|
|
45
|
+
const newSearchParams = new URLSearchParams(window.location.search);
|
|
48
46
|
newSearchParams.set("threadId", conversation.conversationID);
|
|
49
47
|
newSearchParams.delete("userId");
|
|
50
48
|
newSearchParams.delete("groupId");
|
|
51
49
|
newSearchParams.delete("botId");
|
|
52
|
-
|
|
50
|
+
onNavigate === null || onNavigate === void 0 ? void 0 : onNavigate(`${window.location.pathname}?${newSearchParams.toString()}`);
|
|
53
51
|
handleClose();
|
|
54
52
|
}
|
|
55
53
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationByGroupItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ConversationByGroupItem.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ConversationByGroupItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ConversationByGroupItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AAOxF,UAAU,4BAA4B;IACpC,KAAK,EAAE,4BAA4B,CAAC;IACpC,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,QAAA,MAAM,uBAAuB,GAAI,2BAG9B,4BAA4B,4CA2D9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
4
3
|
import { useTranslation } from "react-i18next";
|
|
5
4
|
import useConversationStore from "../../store/conversation";
|
|
6
5
|
import { useChatContext } from "../../context/ChatContext";
|
|
@@ -9,10 +8,7 @@ import GroupCompositeAvatar from "../../components/group/GroupCompositeAvatar";
|
|
|
9
8
|
import ThreadCard from "./ThreadCard";
|
|
10
9
|
const ConversationByGroupItem = ({ group, latestPreview, }) => {
|
|
11
10
|
const { t } = useTranslation();
|
|
12
|
-
const user = useChatContext()
|
|
13
|
-
const router = useRouter();
|
|
14
|
-
const pathname = usePathname();
|
|
15
|
-
const searchParams = useSearchParams();
|
|
11
|
+
const { user, onNavigate } = useChatContext();
|
|
16
12
|
const setConversationData = useConversationStore((state) => state.setConversationData);
|
|
17
13
|
const setSelectedConversationId = useConversationStore((state) => state.setSelectedConversationId);
|
|
18
14
|
const isSelected = useConversationStore((state) => state.selectedConversationId === group.conversationId);
|
|
@@ -20,12 +16,12 @@ const ConversationByGroupItem = ({ group, latestPreview, }) => {
|
|
|
20
16
|
const handleClick = () => {
|
|
21
17
|
setConversationData(conversation);
|
|
22
18
|
setSelectedConversationId(conversation.conversationID);
|
|
23
|
-
const newSearchParams = new URLSearchParams(
|
|
19
|
+
const newSearchParams = new URLSearchParams(window.location.search);
|
|
24
20
|
newSearchParams.set("threadId", conversation.conversationID);
|
|
25
21
|
newSearchParams.delete("userId");
|
|
26
22
|
newSearchParams.delete("groupId");
|
|
27
23
|
newSearchParams.delete("botId");
|
|
28
|
-
|
|
24
|
+
onNavigate === null || onNavigate === void 0 ? void 0 : onNavigate(`${window.location.pathname}?${newSearchParams.toString()}`);
|
|
29
25
|
};
|
|
30
26
|
const latestMsg = (latestPreview === null || latestPreview === void 0 ? void 0 : latestPreview.latestMsg) || "";
|
|
31
27
|
const latestMsgSendTime = (latestPreview === null || latestPreview === void 0 ? void 0 : latestPreview.latestMsgSendTime) || 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationBySessionItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ConversationBySessionItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAE7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"ConversationBySessionItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ConversationBySessionItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAE7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAUhD,UAAU,8BAA8B;IACtC,WAAW,EAAE,gBAAgB,CAAC;IAC9B,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,QAAA,MAAM,yBAAyB,GAAI,iCAGhC,8BAA8B,mDA0EhC,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { useTranslation } from "react-i18next";
|
|
4
4
|
import useConversationStore from "../../store/conversation";
|
|
5
|
-
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
6
5
|
import { Avatar } from "antd";
|
|
7
6
|
import { useChatContext } from "../../context/ChatContext";
|
|
8
7
|
import { useConversationDisplayData } from "../../hooks/conversation/useConversation";
|
|
@@ -13,26 +12,23 @@ import ThreadCard from "./ThreadCard";
|
|
|
13
12
|
const ConversationBySessionItem = ({ sessionItem, latestPreview, }) => {
|
|
14
13
|
var _a;
|
|
15
14
|
const { t } = useTranslation();
|
|
16
|
-
const user = useChatContext()
|
|
15
|
+
const { user, onNavigate } = useChatContext();
|
|
17
16
|
const isSelected = useConversationStore((state) => {
|
|
18
17
|
var _a;
|
|
19
18
|
return state.selectedConversationId ===
|
|
20
19
|
((_a = sessionItem === null || sessionItem === void 0 ? void 0 : sessionItem.conversation) === null || _a === void 0 ? void 0 : _a.conversationID);
|
|
21
20
|
});
|
|
22
21
|
const conversation = sessionItem === null || sessionItem === void 0 ? void 0 : sessionItem.conversation;
|
|
23
|
-
const router = useRouter();
|
|
24
|
-
const pathname = usePathname();
|
|
25
|
-
const searchParams = useSearchParams();
|
|
26
22
|
const setConversationData = useConversationStore((state) => state.setConversationData);
|
|
27
23
|
const setSelectedConversationId = useConversationStore((state) => state.setSelectedConversationId);
|
|
28
24
|
const handleConversationClick = (conversation) => {
|
|
29
25
|
setConversationData(conversation);
|
|
30
|
-
const newSearchParams = new URLSearchParams(
|
|
26
|
+
const newSearchParams = new URLSearchParams(window.location.search);
|
|
31
27
|
newSearchParams.set("threadId", conversation.conversationID);
|
|
32
28
|
newSearchParams.delete("userId");
|
|
33
29
|
newSearchParams.delete("groupId");
|
|
34
30
|
newSearchParams.delete("botId");
|
|
35
|
-
|
|
31
|
+
onNavigate === null || onNavigate === void 0 ? void 0 : onNavigate(`${window.location.pathname}?${newSearchParams.toString()}`);
|
|
36
32
|
setSelectedConversationId(conversation.conversationID);
|
|
37
33
|
};
|
|
38
34
|
const { avatar, displayName = "" } = useConversationDisplayData(conversation || null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AA4BA,QAAA,MAAM,oBAAoB,+
|
|
1
|
+
{"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AA4BA,QAAA,MAAM,oBAAoB,+CAySzB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -68,20 +68,26 @@ const DeskConversationList = () => {
|
|
|
68
68
|
}, [showSearch]);
|
|
69
69
|
useEffect(() => {
|
|
70
70
|
const threadId = searchParams.get("threadId");
|
|
71
|
-
if (threadId) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
71
|
+
if (!threadId) {
|
|
72
|
+
useConversationStore.getState().clearSelectedConversation();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
setSelectedConversationId(threadId);
|
|
76
|
+
const selectedConversation = conversationList.find((conv) => conv.conversationID === threadId);
|
|
77
|
+
if (selectedConversation) {
|
|
78
|
+
setConversationData(selectedConversation);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
DChatSDK.getMultipleConversation([threadId]).then((res) => {
|
|
82
|
+
// threadId can go stale between the fetch starting and resolving
|
|
83
|
+
// (e.g. the user was removed from that group mid-flight) — only
|
|
84
|
+
// apply the result if the URL still points at this conversation.
|
|
85
|
+
if (res.data.length > 0 &&
|
|
86
|
+
searchParams.get("threadId") === threadId) {
|
|
87
|
+
setConversationData(res.data[0]);
|
|
88
|
+
updateConversationList(res.data, "filter");
|
|
89
|
+
}
|
|
90
|
+
});
|
|
85
91
|
}
|
|
86
92
|
}, [searchParams, conversationList]);
|
|
87
93
|
useEffect(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationInboxList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/ConversationInboxList.tsx"],"names":[],"mappings":"
|
|
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;AAMjE,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;CACvD;AAYD,QAAA,MAAM,qBAAqB,GAAI,oFAO5B,0BAA0B,4CA+E5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -1,27 +1,25 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
4
3
|
import { useTranslation } from "react-i18next";
|
|
5
4
|
import { Empty, Spin } from "antd";
|
|
6
5
|
import InfiniteScroll from "react-infinite-scroll-component";
|
|
7
6
|
import useConversationStore from "../../store/conversation";
|
|
7
|
+
import { useChatContext } from "../../context/ChatContext";
|
|
8
8
|
import { Icon } from "../../components/icon";
|
|
9
9
|
import ConversationInboxItem from "./ConversationInboxItem";
|
|
10
10
|
const FooterSkeleton = () => (_jsxs("div", { className: "flex items-center gap-3 p-3", children: [_jsx("div", { className: "h-10 w-10 animate-pulse rounded-full bg-neutral-200" }), _jsxs("div", { className: "flex flex-1 flex-col gap-2", children: [_jsx("div", { className: "h-3 w-1/2 animate-pulse rounded bg-neutral-200" }), _jsx("div", { className: "h-2.5 w-1/3 animate-pulse rounded bg-neutral-200" })] })] }));
|
|
11
11
|
const ConversationInboxList = ({ items, isLoading, isFetchingNextPage, hasNextPage, onLoadMore, onSelectThread, }) => {
|
|
12
12
|
const { t } = useTranslation("conversation-inbox");
|
|
13
|
-
const
|
|
14
|
-
const pathname = usePathname();
|
|
15
|
-
const searchParams = useSearchParams();
|
|
13
|
+
const { onNavigate } = useChatContext();
|
|
16
14
|
const setConversationData = useConversationStore((state) => state.setConversationData);
|
|
17
15
|
const setSelectedConversationId = useConversationStore((state) => state.setSelectedConversationId);
|
|
18
16
|
const handleSelectThread = (item) => {
|
|
19
|
-
const newSearchParams = new URLSearchParams(
|
|
17
|
+
const newSearchParams = new URLSearchParams(window.location.search);
|
|
20
18
|
newSearchParams.set("threadId", item.conversationID);
|
|
21
19
|
newSearchParams.delete("userId");
|
|
22
20
|
newSearchParams.delete("groupId");
|
|
23
21
|
newSearchParams.delete("botId");
|
|
24
|
-
|
|
22
|
+
onNavigate === null || onNavigate === void 0 ? void 0 : onNavigate(`${window.location.pathname}?${newSearchParams.toString()}`);
|
|
25
23
|
setSelectedConversationId(item.conversationID);
|
|
26
24
|
setConversationData(item);
|
|
27
25
|
onSelectThread === null || onSelectThread === void 0 ? void 0 : onSelectThread(item);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupMembersDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/message/GroupMembersDrawer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GroupMembersDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/message/GroupMembersDrawer.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAiB/C,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA0CD,QAAA,MAAM,kBAAkB,GAAI,wDAKzB,uBAAuB,4CA2iBzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { GroupMemberRole } from "@droppii-org/wasm-client-sdk";
|
|
3
|
-
import { Avatar, Button, Drawer, Dropdown, Empty, Input, message,
|
|
3
|
+
import { Avatar, Button, Drawer, Dropdown, Empty, Input, message, Spin } from "antd";
|
|
4
|
+
import ConfirmModal from "../../components/common/ConfirmModal";
|
|
4
5
|
import { useEffect, useMemo, useState } from "react";
|
|
5
6
|
import { useDebounce } from "ahooks";
|
|
6
7
|
import { useTranslation } from "react-i18next";
|
|
7
|
-
import {
|
|
8
|
+
import { useChatContext } from "../../context/ChatContext";
|
|
8
9
|
import useAuthStore from "../../store/auth";
|
|
9
10
|
import useConversationStore from "../../store/conversation";
|
|
10
11
|
import { useGroupMembers } from "../../hooks/group/useGroupMembers";
|
|
@@ -33,8 +34,7 @@ const getMemberRoleLabel = ({ member, customerUserID, t, }) => {
|
|
|
33
34
|
const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled = false, }) => {
|
|
34
35
|
var _a, _b;
|
|
35
36
|
const { t } = useTranslation();
|
|
36
|
-
const
|
|
37
|
-
const pathname = usePathname();
|
|
37
|
+
const { onNavigate } = useChatContext();
|
|
38
38
|
const [isOpen, setIsOpen] = useState(false);
|
|
39
39
|
const [showLeaveConfirm, setShowLeaveConfirm] = useState(false);
|
|
40
40
|
const [showAddMember, setShowAddMember] = useState(false);
|
|
@@ -238,7 +238,7 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
|
|
|
238
238
|
try {
|
|
239
239
|
await leaveConversation({ conversationId });
|
|
240
240
|
message.success(t("leave_group_success"));
|
|
241
|
-
|
|
241
|
+
onNavigate === null || onNavigate === void 0 ? void 0 : onNavigate(window.location.pathname);
|
|
242
242
|
setShowLeaveConfirm(false);
|
|
243
243
|
setIsOpen(false);
|
|
244
244
|
}
|
|
@@ -360,11 +360,11 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
|
|
|
360
360
|
userID: adminPermissionMember.userID,
|
|
361
361
|
permissions: adminPermissionMember.permissions,
|
|
362
362
|
}
|
|
363
|
-
: undefined, onMemberPermissionsSaved: patchMemberPermissions })), _jsx(
|
|
363
|
+
: undefined, onMemberPermissionsSaved: patchMemberPermissions })), _jsx(ConfirmModal, { open: showLeaveConfirm, onOk: handleConfirmLeave, onCancel: () => setShowLeaveConfirm(false), title: t("leave_group_confirm_title"), okText: t("leave_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isLeaving, children: _jsx("p", { children: t("leave_group_confirm_message") }) }), _jsx(ConfirmModal, { open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "remove", onOk: handleConfirmRemoveMember, onCancel: () => setConfirmMemberAction(null), title: t("remove_member_confirm_title"), okText: t("remove_from_group"), cancelText: t("cancel"), okType: "danger", children: _jsx("p", { children: t("remove_member_confirm_message", {
|
|
364
364
|
name: confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.member.nickname,
|
|
365
|
-
}) }) }), _jsx(
|
|
365
|
+
}) }) }), _jsx(ConfirmModal, { open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "transfer-owner", onOk: handleConfirmTransferOwner, onCancel: () => setConfirmMemberAction(null), title: t("transfer_owner_confirm_title"), okText: t("transfer_owner"), cancelText: t("cancel"), okType: "danger", children: _jsx("p", { children: t("transfer_owner_confirm_message", {
|
|
366
366
|
name: confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.member.nickname,
|
|
367
|
-
}) }) }), _jsx(
|
|
367
|
+
}) }) }), _jsx(ConfirmModal, { open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "assign-admin", onOk: handleConfirmAssignAdmin, onCancel: () => setConfirmMemberAction(null), title: t("assign_admin_confirm_title"), okText: t("agree"), cancelText: t("cancel"), children: _jsx("p", { children: t("assign_admin_confirm_message", {
|
|
368
368
|
name: confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.member.nickname,
|
|
369
369
|
}) }) })] }));
|
|
370
370
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAgCA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAgS3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useMessage } from "../../hooks/message/useMessage";
|
|
4
|
-
import { Button, Empty,
|
|
4
|
+
import { Button, Empty, Spin, message as toastMessage } from "antd";
|
|
5
5
|
import { useCallback, useEffect, useState } from "react";
|
|
6
6
|
import dayjs from "dayjs";
|
|
7
7
|
import isToday from "dayjs/plugin/isToday";
|
|
8
|
+
import { GroupMemberRole, GroupStatus } from "@droppii-org/wasm-client-sdk";
|
|
8
9
|
import emitter from "../../utils/events";
|
|
9
10
|
import MessageItem from "./item";
|
|
10
11
|
import MessageInfiniteScroll from "./MessageInfiniteScroll";
|
|
@@ -24,6 +25,7 @@ import { useGroupPermission } from "../../hooks/group/useGroupPermission";
|
|
|
24
25
|
import { isGroupSession } from "../../utils/imCommon";
|
|
25
26
|
import { ConnectStatus, SessionStatus } from "../../types/chat";
|
|
26
27
|
import PinLimitModal from "../../components/conversation-detail/PinLimitModal";
|
|
28
|
+
import ConfirmModal from "../../components/common/ConfirmModal";
|
|
27
29
|
dayjs.extend(isToday);
|
|
28
30
|
const MessageList = (props) => {
|
|
29
31
|
const { t } = useTranslation();
|
|
@@ -32,7 +34,19 @@ const MessageList = (props) => {
|
|
|
32
34
|
const conversationData = useConversationStore((state) => state.conversationData);
|
|
33
35
|
const permissions = useGroupPermission(conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID);
|
|
34
36
|
const isGroupChat = isGroupSession(conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationType);
|
|
35
|
-
const
|
|
37
|
+
const currentGroupInfo = useConversationStore((state) => state.currentGroupInfo);
|
|
38
|
+
const currentMemberInGroup = useConversationStore((state) => state.currentMemberInGroup);
|
|
39
|
+
// Group/member data refetches async on conversation switch and can briefly
|
|
40
|
+
// hold the previous conversation's groupID or a not-yet-loaded roleLevel.
|
|
41
|
+
const isGroupStateFresh = !isGroupChat ||
|
|
42
|
+
((currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupID) === (conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID) &&
|
|
43
|
+
(currentMemberInGroup === null || currentMemberInGroup === void 0 ? void 0 : currentMemberInGroup.groupID) === (conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID) &&
|
|
44
|
+
(currentMemberInGroup === null || currentMemberInGroup === void 0 ? void 0 : currentMemberInGroup.roleLevel) !== undefined);
|
|
45
|
+
// Group-wide mute (GroupThreadInfo.tsx) restricts Normal members only.
|
|
46
|
+
const isRestrictedByGroupMute = isGroupChat &&
|
|
47
|
+
(currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.status) === GroupStatus.Muted &&
|
|
48
|
+
(currentMemberInGroup === null || currentMemberInGroup === void 0 ? void 0 : currentMemberInGroup.roleLevel) === GroupMemberRole.Normal;
|
|
49
|
+
const canSendMessage = !isGroupChat || (permissions.sendMessage && !isRestrictedByGroupMute);
|
|
36
50
|
const canPinMessage = !isGroupChat || permissions.pinMessage;
|
|
37
51
|
const setQuotedMessage = useConversationStore((state) => state.setQuotedMessage);
|
|
38
52
|
const setSearchClientMsgID = useConversationStore((state) => state.setSearchClientMsgID);
|
|
@@ -136,6 +150,6 @@ const MessageList = (props) => {
|
|
|
136
150
|
if (!conversationData) {
|
|
137
151
|
return (_jsx("div", { className: "flex flex-1 items-center justify-center h-full", children: connectStatus !== ConnectStatus.Connected ? (_jsx(Spin, {})) : (_jsx(Empty, { description: t("no_conversation_data") })) }));
|
|
138
152
|
}
|
|
139
|
-
return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full min-w-0 bg-white", style: { overflowX: "hidden" }, children: [_jsx(MessageHeader, { onClose: onClose, currentSession: latestConversationSession, isJoined: isJoined, onOpenThreadInfo: onOpenThreadInfo }), _jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array, contextMenuOpen: openMenuId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenMenuId(open ? message.clientMsgID : null), onRevokeMessage: handleOpenRevoke, onQuoteMessage: setQuotedMessage, onPressQuoteMessage: onPressQuoteMessage, onPinMessage: canPinMessage ? handlePinMessage : undefined, onUnpinMessage: canPinMessage ? handleUnpinMessage : undefined }, message.clientMsgID))) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), isCheckingMembership ? (_jsx("div", { className: "border-t bg-white py-4 flex items-center justify-center", children: _jsx(Spin, {}) })) : (latestConversationSession === null || latestConversationSession === void 0 ? void 0 : latestConversationSession.status) === SessionStatus.UNASSIGNED ? (_jsx(UnassignedSessionFooter, { sessionId: latestConversationSession.id, teamId: latestConversationSession.teamId })) : shouldRestrictToLastSession ? (_jsxs("div", { className: "border-t bg-white py-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-sm text-gray-500", children: t("join_group_required") }), _jsx(Button, { type: "primary", onClick: joinGroup, loading: isJoining, children: t("join_group") })] })) : !canSendMessage ? (_jsx("div", { className: "border-t bg-[#f5f5f5] py-3 flex items-center justify-center", children: _jsx("p", { className: "text-sm text-gray-500", children: t("send_message_disabled") }) })) : (_jsx(MessageFooter, { currentSession: latestConversationSession, openCreateCannedModal: openCreateCannedModal })), _jsx(
|
|
153
|
+
return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full min-w-0 bg-white", style: { overflowX: "hidden" }, children: [_jsx(MessageHeader, { onClose: onClose, currentSession: latestConversationSession, isJoined: isJoined, onOpenThreadInfo: onOpenThreadInfo }), _jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array, contextMenuOpen: openMenuId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenMenuId(open ? message.clientMsgID : null), onRevokeMessage: handleOpenRevoke, onQuoteMessage: setQuotedMessage, onPressQuoteMessage: onPressQuoteMessage, onPinMessage: canPinMessage ? handlePinMessage : undefined, onUnpinMessage: canPinMessage ? handleUnpinMessage : undefined }, message.clientMsgID))) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), isCheckingMembership || !isGroupStateFresh ? (_jsx("div", { className: "border-t bg-white py-4 flex items-center justify-center", children: _jsx(Spin, {}) })) : (latestConversationSession === null || latestConversationSession === void 0 ? void 0 : latestConversationSession.status) === SessionStatus.UNASSIGNED ? (_jsx(UnassignedSessionFooter, { sessionId: latestConversationSession.id, teamId: latestConversationSession.teamId })) : shouldRestrictToLastSession ? (_jsxs("div", { className: "border-t bg-white py-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-sm text-gray-500", children: t("join_group_required") }), _jsx(Button, { type: "primary", onClick: joinGroup, loading: isJoining, children: t("join_group") })] })) : !canSendMessage ? (_jsx("div", { className: "border-t bg-[#f5f5f5] py-3 flex items-center justify-center", children: _jsx("p", { className: "text-sm text-gray-500", children: t(isRestrictedByGroupMute ? "send_message_disabled_group_mute" : "send_message_disabled") }) })) : (_jsx(MessageFooter, { currentSession: latestConversationSession, openCreateCannedModal: openCreateCannedModal })), _jsx(ConfirmModal, { open: showConfirmRevoke, onOk: onRevokeMessage, onCancel: handleCloseRevoke, title: t("revoke_message_confirm_title"), okText: t("revoke"), cancelText: t("cancel"), okType: "danger", confirmLoading: isRevoking, children: _jsx("p", { children: t("revoke_message_confirm_message") }) }), _jsx(PinLimitModal, { open: pinLimitModalOpen, max: pinnedTotalCount, onClose: () => setPinLimitModalOpen(false) })] }));
|
|
140
154
|
};
|
|
141
155
|
export default MessageList;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
2
|
export interface MessageBubbleProps {
|
|
3
3
|
isMine: boolean;
|
|
4
4
|
content: ReactNode;
|
|
@@ -8,7 +8,8 @@ export interface MessageBubbleProps {
|
|
|
8
8
|
isInternal?: boolean;
|
|
9
9
|
id?: string;
|
|
10
10
|
isTransparent?: boolean;
|
|
11
|
+
timeLabel?: string;
|
|
11
12
|
}
|
|
12
|
-
declare const MessageBubble: ({ isMine, content, senderName, showSenderName, showTip, isInternal, id, isTransparent, }: MessageBubbleProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
declare const MessageBubble: ({ isMine, content, senderName, showSenderName, showTip, isInternal, id, isTransparent, timeLabel, }: MessageBubbleProps) => import("react/jsx-runtime").JSX.Element;
|
|
13
14
|
export default MessageBubble;
|
|
14
15
|
//# sourceMappingURL=MessageBubble.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageBubble.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/MessageBubble.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"MessageBubble.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/MessageBubble.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEjD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,SAAS,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA4CD,QAAA,MAAM,aAAa,GAAI,qGAUpB,kBAAkB,4CAiEpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import clsx from "clsx";
|
|
4
|
+
import { useState } from "react";
|
|
4
5
|
const INCOMING_TAIL_PATH = "M1.3798 18H4V0C3.51762 4.5 3.34269 10.5 0.966518 14C-0.568384 16.2608 -0.159364 18 1.3798 18Z";
|
|
5
6
|
const OUTGOING_TAIL_PATH = "M2.6202 18H0V0C0.482375 4.5 0.657308 10.5 3.03348 14C4.56838 16.2608 4.15936 18 2.6202 18Z";
|
|
6
7
|
const MessageBubbleTail = ({ isMine, isInternal, }) => (_jsx("div", { className: clsx("flex shrink-0 items-center justify-center", isInternal
|
|
@@ -8,8 +9,10 @@ const MessageBubbleTail = ({ isMine, isInternal, }) => (_jsx("div", { className:
|
|
|
8
9
|
: isMine
|
|
9
10
|
? "text-chat-bubble-mine"
|
|
10
11
|
: "text-chat-bubble-neutral"), children: _jsx("div", { className: "flex-none", children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "4", height: "18", viewBox: "0 0 4 18", fill: "none", "aria-hidden": true, children: _jsx("path", { d: isMine ? OUTGOING_TAIL_PATH : INCOMING_TAIL_PATH, fill: "currentColor", fillOpacity: "0.1" }) }) }) }));
|
|
11
|
-
const MessageBubble = ({ isMine, content, senderName, showSenderName, showTip = true, isInternal = false, id, isTransparent = false, }) => {
|
|
12
|
+
const MessageBubble = ({ isMine, content, senderName, showSenderName, showTip = true, isInternal = false, id, isTransparent = false, timeLabel, }) => {
|
|
12
13
|
const showTail = showTip && !isTransparent;
|
|
14
|
+
const [timeRevealed, setTimeRevealed] = useState(false);
|
|
15
|
+
const showTimeLabel = Boolean(timeLabel) && (showTip || timeRevealed);
|
|
13
16
|
const bubbleClass = clsx("relative max-w-full", isTransparent
|
|
14
17
|
? "bg-transparent p-0"
|
|
15
18
|
: clsx("p-2", showTip
|
|
@@ -21,6 +24,9 @@ const MessageBubble = ({ isMine, content, senderName, showSenderName, showTip =
|
|
|
21
24
|
: isMine
|
|
22
25
|
? "bg-chat-bubble-mine/10"
|
|
23
26
|
: "bg-chat-bubble-neutral/10"));
|
|
24
|
-
return (_jsxs("div", { className: "relative flex items-end", "data-testid": "message-bubble",
|
|
27
|
+
return (_jsxs("div", { className: "relative flex items-end", "data-testid": "message-bubble", onClick: () => {
|
|
28
|
+
if (!showTip && timeLabel)
|
|
29
|
+
setTimeRevealed((prev) => !prev);
|
|
30
|
+
}, children: [!isMine && showTail && (_jsx(MessageBubbleTail, { isMine: isMine, isInternal: isInternal })), _jsx("div", { className: bubbleClass, id: id, children: _jsxs("div", { className: clsx("flex flex-col gap-1", !isTransparent && "px-1"), children: [showSenderName && senderName && (_jsx("span", { className: "text-[12px] font-medium leading-[160%] tracking-[0.12px] text-gray-400", children: senderName })), _jsx("div", { className: "flex flex-col gap-2", children: content })] }) }), isMine && showTail && (_jsx(MessageBubbleTail, { isMine: isMine, isInternal: isInternal })), showTimeLabel && (_jsx("span", { "data-testid": "message-time-label", className: clsx("absolute -bottom-2 flex h-[19px] w-[30px] items-center justify-center rounded-full bg-white text-[10px] text-gray-400 shadow-sm", isMine ? "right-1" : "left-1"), children: timeLabel }))] }));
|
|
25
31
|
};
|
|
26
32
|
export default MessageBubble;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,IAAI,eAAe,EAG/B,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,IAAI,eAAe,EAG/B,MAAM,8BAA8B,CAAC;AAmCtC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAClD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAyBD,QAAA,MAAM,WAAW,GAAI,qMAalB,gBAAgB,mDA+SlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -8,7 +8,8 @@ import MessageBubble from "./MessageBubble";
|
|
|
8
8
|
import { renderBubbleContent } from "./renderMessageContent";
|
|
9
9
|
import { getVisibleNeighbor, isMessageHiddenForViewer, } from "../../../hooks/message/useMessage";
|
|
10
10
|
import { MSG_ITEM_CONTENT_PREFIX, MSG_ITEM_PREFIX } from "../../../constants";
|
|
11
|
-
import {
|
|
11
|
+
import { formatDividerTimestamp } from "../../../utils/common";
|
|
12
|
+
import { CustomMessageType } from "../../../types/customMessage";
|
|
12
13
|
import useAuthStore from "../../../store/auth";
|
|
13
14
|
import useConversationStore from "../../../store/conversation";
|
|
14
15
|
import { useMemo, useRef } from "react";
|
|
@@ -22,6 +23,9 @@ import GroupNotificationMessageItem from "./GroupNotificationMessage";
|
|
|
22
23
|
import { isGroupNotificationMessageType, isSystemLogMessageType } from "../../../utils/messageLog";
|
|
23
24
|
import { buildMessageToolboxMenuItems, getCopyableMessageText, isCopyableMessageType, isPinnableMessageType, MessageToolboxActionKey, MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, useMessageToolboxVisibility, } from "../../../components/message/toolbox";
|
|
24
25
|
const MESSAGE_AVATAR_SIZE = 24;
|
|
26
|
+
const DIVIDER_GAP_MINUTES = 30;
|
|
27
|
+
const GROUPING_GAP_MINUTES = 5;
|
|
28
|
+
const isOrderMessage = (message) => { var _a; return ((_a = message === null || message === void 0 ? void 0 : message.customElem) === null || _a === void 0 ? void 0 : _a.extension) === CustomMessageType.Order; };
|
|
25
29
|
const MessageAvatar = ({ avatarUrl, senderNickname, }) => {
|
|
26
30
|
var _a;
|
|
27
31
|
return (_jsx(Avatar, { size: MESSAGE_AVATAR_SIZE, src: avatarUrl, className: "shrink-0 self-end", children: ((_a = senderNickname === null || senderNickname === void 0 ? void 0 : senderNickname.charAt) === null || _a === void 0 ? void 0 : _a.call(senderNickname, 0)) || "A" }));
|
|
@@ -127,10 +131,23 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
|
|
|
127
131
|
message.clientMsgID;
|
|
128
132
|
const previousMessage = getVisibleNeighbor(allMessages, message, "prev");
|
|
129
133
|
const nextMessage = getVisibleNeighbor(allMessages, message, "next");
|
|
130
|
-
const
|
|
131
|
-
const
|
|
134
|
+
const isOrder = isOrderMessage(message);
|
|
135
|
+
const prevSameUser = !isOrder &&
|
|
136
|
+
!!previousMessage &&
|
|
137
|
+
!isOrderMessage(previousMessage) &&
|
|
138
|
+
previousMessage.sendID === (message === null || message === void 0 ? void 0 : message.sendID) &&
|
|
139
|
+
Math.abs(dayjs(message.sendTime).diff(previousMessage.sendTime, "minute")) <=
|
|
140
|
+
GROUPING_GAP_MINUTES;
|
|
141
|
+
const nextSameUser = !isOrder &&
|
|
142
|
+
!!nextMessage &&
|
|
143
|
+
!isOrderMessage(nextMessage) &&
|
|
144
|
+
nextMessage.sendID === (message === null || message === void 0 ? void 0 : message.sendID) &&
|
|
145
|
+
Math.abs(dayjs(nextMessage.sendTime).diff(message.sendTime, "minute")) <=
|
|
146
|
+
GROUPING_GAP_MINUTES;
|
|
132
147
|
const showTimeBreak = !previousMessage ||
|
|
133
|
-
!dayjs(message.sendTime).isSame(previousMessage.sendTime, "days")
|
|
148
|
+
!dayjs(message.sendTime).isSame(previousMessage.sendTime, "days") ||
|
|
149
|
+
Math.abs(dayjs(message.sendTime).diff(previousMessage.sendTime, "minute")) >
|
|
150
|
+
DIVIDER_GAP_MINUTES;
|
|
134
151
|
const showPeerInfo = isGroupChat || showSenderInfo;
|
|
135
152
|
const showAvatar = showPeerInfo && !isMine && !nextSameUser;
|
|
136
153
|
const showSenderName = showPeerInfo && !isMine && !prevSameUser;
|
|
@@ -142,7 +159,7 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
|
|
|
142
159
|
className: "flex flex-col gap-2 py-1 px-3 sm:px-4 min-w-0",
|
|
143
160
|
id: `${MSG_ITEM_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`,
|
|
144
161
|
};
|
|
145
|
-
const timeBreakNode = showTimeBreak ? (_jsx("div", { className: "flex justify-center", children: _jsx("span", { className: "rounded-full bg-neutral-100 px-2 py-1 text-center text-xs text-gray-600", children:
|
|
162
|
+
const timeBreakNode = showTimeBreak ? (_jsx("div", { className: "flex justify-center", children: _jsx("span", { className: "rounded-full bg-neutral-100 px-2 py-1 text-center text-xs text-gray-600", children: formatDividerTimestamp(message.sendTime) }) })) : null;
|
|
146
163
|
if (isSystemLogMessage) {
|
|
147
164
|
return (_createElement("div", Object.assign({}, messageContainerProps, { key: message === null || message === void 0 ? void 0 : message.clientMsgID }),
|
|
148
165
|
timeBreakNode,
|
|
@@ -153,7 +170,7 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
|
|
|
153
170
|
timeBreakNode,
|
|
154
171
|
_jsx(GroupNotificationMessageItem, { message: message })));
|
|
155
172
|
}
|
|
156
|
-
const bubbleNode = (_jsx(MessageBubble, { isMine: isMine, isInternal: isInternalMessage, senderName: message === null || message === void 0 ? void 0 : message.senderNickname, showSenderName: showSenderName, showTip: showTip, id: `${MSG_ITEM_CONTENT_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`, content: renderBubbleContent(message, onPressQuoteMessage), isTransparent: isStickerMessage }));
|
|
173
|
+
const bubbleNode = (_jsx(MessageBubble, { isMine: isMine, isInternal: isInternalMessage, senderName: message === null || message === void 0 ? void 0 : message.senderNickname, showSenderName: showSenderName, showTip: showTip, id: `${MSG_ITEM_CONTENT_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`, content: renderBubbleContent(message, onPressQuoteMessage), isTransparent: isStickerMessage, timeLabel: dayjs.tz(message.sendTime).format("HH:mm") }));
|
|
157
174
|
const showPinnedBadge = Boolean(message === null || message === void 0 ? void 0 : message.isPinned);
|
|
158
175
|
const pinnedBadgeNode = showPinnedBadge ? (_jsx("span", { "data-testid": "message-pinned-badge", className: clsx("absolute -top-2.5 z-[1] flex h-[22px] w-[26px] items-center justify-center rounded-full border border-white bg-gray-25", isMine ? "left-0" : "right-0"), children: _jsx(Icon, { icon: "thumbtack-b", size: 12, className: "text-primary-400" }) })) : null;
|
|
159
176
|
const wrappedBubble = hasContextMenu ? (_jsx(Dropdown, { menu: { items: contextMenuItems }, trigger: ["contextMenu"], open: contextMenuOpen, onOpenChange: onContextMenuOpenChange, overlayClassName: MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, children: _jsxs("div", { ref: bubbleWrapperRef, className: "relative min-w-0", children: [bubbleNode, pinnedBadgeNode] }) })) : (_jsxs("div", { className: "relative min-w-0", children: [bubbleNode, pinnedBadgeNode] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/GroupThreadInfo.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GroupThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/GroupThreadInfo.tsx"],"names":[],"mappings":"AAoBA,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;AAID,QAAA,MAAM,eAAe,GAAI,qBAAqB,oBAAoB,mDAyjBjE,CAAC;AAEF,eAAe,eAAe,CAAC"}
|