@droppii-org/chat-sdk
Version:
Droppii React Chat SDK
155 lines (154 loc) • 8.52 kB
JavaScript
"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useMessage } from "../../hooks/message/useMessage";
import { Empty, Spin } from "antd";
import { useEffect, useMemo, useRef } from "react";
import dayjs from "dayjs";
import isToday from "dayjs/plugin/isToday";
import emitter from "../../utils/events";
import MessageItem from "./item";
import InfiniteScroll from "react-infinite-scroll-component";
import MessageHeader from "./MessageHeader";
import MessageFooter from "./footer";
import { images } from "../../constants/images";
import { useTranslation } from "react-i18next";
import useConversationStore from "../../store/conversation";
import { isNumber } from "lodash";
import { useDebounceFn } from "ahooks";
import { MSG_ITEM_CONTENT_PREFIX, MSG_ITEM_PREFIX } from "../../constants";
import { markConversationMessageAsRead } from "../../hooks/conversation/useConversation";
import { useChatContext } from "../../context/ChatContext";
import { useGetSession } from "../../hooks/session/useGetSession";
dayjs.extend(isToday);
const BOTTOM_THRESHOLD = -5;
const MessageList = (props) => {
var _a;
const { t } = useTranslation();
const { user } = useChatContext();
const { onClose, conversationId, searchClientMsgID } = props;
const scrollRef = useRef(null);
const { getMoreOldMessages, moreOldLoading, loadState, getMoreNewMessages, moreNewLoading, latestLoadState, } = useMessage(conversationId, searchClientMsgID);
const conversationData = useConversationStore((state) => state.conversationData);
const { dataFlatten: sessions, refetch: refetchSession } = useGetSession({
filter: {
conversationIds: !!conversationId ? [conversationId] : [],
},
});
const currentSession = useMemo(() => {
return sessions === null || sessions === void 0 ? void 0 : sessions.find((session) => session.conversationId === conversationId);
}, [sessions, conversationId]);
const handleMarkConversationMessageAsRead = () => {
var _a, _b, _c, _d, _e;
const lastMessage = (_b = (_a = latestLoadState === null || latestLoadState === void 0 ? void 0 : latestLoadState.current) === null || _a === void 0 ? void 0 : _a.messageList) === null || _b === void 0 ? void 0 : _b[0];
if (!((_c = latestLoadState === null || latestLoadState === void 0 ? void 0 : latestLoadState.current) === null || _c === void 0 ? void 0 : _c.hasMoreNew) &&
!moreNewLoading &&
(lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.isRead) === false &&
(lastMessage === null || lastMessage === void 0 ? void 0 : lastMessage.sendID) !== (user === null || user === void 0 ? void 0 : user.userID) &&
isNumber((_d = scrollRef.current) === null || _d === void 0 ? void 0 : _d.scrollTop) &&
((_e = scrollRef.current) === null || _e === void 0 ? void 0 : _e.scrollTop) >= BOTTOM_THRESHOLD) {
markConversationMessageAsRead(conversationId);
}
};
const scrollToBottom = () => {
handleMarkConversationMessageAsRead();
setTimeout(() => {
var _a, _b, _c, _d;
if (isNumber((_a = scrollRef.current) === null || _a === void 0 ? void 0 : _a.scrollTop) &&
((_b = scrollRef.current) === null || _b === void 0 ? void 0 : _b.scrollTop) >= BOTTOM_THRESHOLD) {
return;
}
(_c = scrollRef.current) === null || _c === void 0 ? void 0 : _c.scrollTo({
top: (_d = scrollRef.current) === null || _d === void 0 ? void 0 : _d.scrollHeight,
behavior: "smooth",
});
});
};
const scrollToMessage = (clientMsgID) => {
setTimeout(() => {
const targetElement = document.getElementById(`${MSG_ITEM_PREFIX}${clientMsgID}`);
targetElement === null || targetElement === void 0 ? void 0 : targetElement.scrollIntoView({
behavior: "auto",
block: "center",
});
setTimeout(() => {
const targetContentElement = document.getElementById(`${MSG_ITEM_CONTENT_PREFIX}${clientMsgID}`);
targetContentElement === null || targetContentElement === void 0 ? void 0 : targetContentElement.classList.add("zoom-in-out-element", "border-blue-500", "border");
// Khi animation kết thúc thì remove element
const onEnd = () => {
targetContentElement === null || targetContentElement === void 0 ? void 0 : targetContentElement.classList.remove("zoom-in-out-element", "border-blue-500", "border");
targetContentElement === null || targetContentElement === void 0 ? void 0 : targetContentElement.removeEventListener("animationend", onEnd);
};
targetContentElement === null || targetContentElement === void 0 ? void 0 : targetContentElement.addEventListener("animationend", onEnd, {
once: true,
});
}, 500);
}, 200);
};
const loadMoreOldMessage = () => {
if (!loadState.hasMoreOld || moreOldLoading)
return;
getMoreOldMessages();
};
const { run: loadMoreNewMessage } = useDebounceFn(() => {
if (!loadState.hasMoreNew || moreNewLoading)
return;
getMoreNewMessages();
}, { wait: 200 });
useEffect(() => {
emitter.on("CHAT_LIST_SCROLL_TO_BOTTOM", scrollToBottom);
emitter.on("CHAT_LIST_SCROLL_TO_MESSAGE", scrollToMessage);
return () => {
emitter.off("CHAT_LIST_SCROLL_TO_BOTTOM", scrollToBottom);
emitter.off("CHAT_LIST_SCROLL_TO_MESSAGE", scrollToMessage);
};
}, []);
useEffect(() => {
emitter.on("UPDATE_SESSION", (sessionUpdated) => {
if (sessionUpdated.conversationId === conversationId) {
refetchSession();
}
});
return () => {
emitter.off("UPDATE_SESSION", () => {
refetchSession();
});
};
}, [conversationId]);
useEffect(() => {
if (!loadState.hasMoreNew && !loadState.initLoading) {
handleMarkConversationMessageAsRead();
}
}, [
loadState.hasMoreNew,
loadState.initLoading,
handleMarkConversationMessageAsRead,
]);
if (!conversationData) {
return (_jsx("div", { className: "flex flex-1 items-center justify-center h-full", children: _jsx(Empty, { description: t("no_conversation_data") }) }));
}
return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full min-w-0", style: {
backgroundImage: `url(${images.conversationBg})`,
backgroundSize: "cover",
backgroundPosition: "center",
overflowX: "hidden",
}, children: [_jsx(MessageHeader, { onClose: onClose, currentSession: currentSession }), _jsx("div", { id: "scrollableMessagesDiv", ref: scrollRef, style: {
height: "100%",
overflowY: "auto",
overflowX: "hidden",
display: "flex",
flexDirection: "column-reverse",
paddingBottom: 12,
}, children: _jsx(InfiniteScroll, { dataLength: ((_a = loadState.messageList) === null || _a === void 0 ? void 0 : _a.length) || 0, next: loadMoreOldMessage, style: {
display: "flex",
flexDirection: "column-reverse",
minWidth: 0,
width: "100%"
}, inverse: true, hasMore: loadState.hasMoreOld, loader: _jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) }), scrollableTarget: "scrollableMessagesDiv", onScroll: (e) => {
const target = e.target;
if (target.scrollTop > BOTTOM_THRESHOLD) {
handleMarkConversationMessageAsRead();
loadMoreNewMessage();
}
}, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array }, message.clientMsgID))) }) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), _jsx(MessageFooter, { currentSession: currentSession })] }));
};
export default MessageList;