UNPKG

@droppii-org/chat-sdk

Version:

Droppii React Chat SDK

155 lines (154 loc) 8.52 kB
"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;