{spaceWelcome
? spaceWelcome.title
: hasNoSelection
? "Chọn một cuộc trò chuyện"
: dmUser
? `Bắt đầu trò chuyện với ${dmUser.name}`
: "Chưa có tin nhắn nào"}
{spaceWelcome
? spaceWelcome.description
: hasNoSelection
? "Hãy chọn một ngườii bạn bên trái để bắt đầu nhắn tin."
: dmUser
? "Hãy gửi lờii chào hoặc câu hỏi để bắt đầu cuộc trò chuyện đầu tiên nhé!"
: "Chọn một cuộc trò chuyện để bắt đầu nhắn tin."}
);
}
function ChatMessages({
isDark,
chatMessages,
dmUser,
onReply,
onEdit,
onShowProfile,
hasNoSelection,
spaceWelcome,
isKnownEmpty,
sendingMessages,
isLoading,
conversationId,
roomId,
onRetry,
}) {
const dispatch = useDispatch();
const messagesContainerRef = useRef(null);
const [isLoadingMore, setIsLoadingMore] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const prevLoadingRef = useRef(isLoading);
const prevMessagesLengthRef = useRef(chatMessages.length);
const prevConversationIdRef = useRef(conversationId);
const hasMoreMessagesRef = useRef(true);
// Track if we have cached messages displayed while background loading
const hasCachedMessages = chatMessages.length > 0 && isLoading;
// Reset pagination state when conversation or room changes
useEffect(() => {
setCurrentPage(1);
hasMoreMessagesRef.current = true;
}, [conversationId, roomId]);
// Auto scroll to bottom when loading finishes, new messages arrive, or conversation changes
useEffect(() => {
const container = messagesContainerRef.current;
if (!container) return;
// Scroll to bottom when conversation changes
if (prevConversationIdRef.current !== conversationId) {
container.scrollTop = container.scrollHeight;
}
// Scroll to bottom when loading finishes
if (prevLoadingRef.current && !isLoading) {
container.scrollTop = container.scrollHeight;
}
// Scroll to bottom when new messages added (but not when loading more)
if (chatMessages.length > prevMessagesLengthRef.current && !isLoadingMore) {
container.scrollTop = container.scrollHeight;
}
prevLoadingRef.current = isLoading;
prevMessagesLengthRef.current = chatMessages.length;
prevConversationIdRef.current = conversationId;
}, [isLoading, chatMessages.length, isLoadingMore, conversationId]);
// Handle scroll event to detect when user reaches the top
const handleScroll = useCallback(
(e) => {
const container = e.target;
// Check if scrolled to top (within 10px threshold)
if (
container.scrollTop < 10 &&
!isLoadingMore &&
hasMoreMessagesRef.current
) {
// DM pagination
if (
conversationId &&
!conversationId.toString().startsWith("temp-conv-")
) {
setIsLoadingMore(true);
const nextPage = currentPage + 1;
dispatch(
fetchMessages({
conversationId,
page: nextPage,
limit: 50,
}),
)
.unwrap()
.then((result) => {
const fetched = result.messages || [];
if (fetched.length === 0) {
hasMoreMessagesRef.current = false;
} else {
setCurrentPage(nextPage);
}
})
.catch((err) => {
console.error("[ChatMessages] Failed to load more DM:", err);
})
.finally(() => {
setIsLoadingMore(false);
});
}
// Room pagination
else if (roomId) {
setIsLoadingMore(true);
const nextPage = currentPage + 1;
dispatch(
fetchRoomMessages({
roomId,
page: nextPage,
limit: 50,
}),
)
.unwrap()
.then((result) => {
const fetched = result.messages || [];
if (fetched.length === 0) {
hasMoreMessagesRef.current = false;
} else {
setCurrentPage(nextPage);
}
})
.catch((err) => {
console.error("[ChatMessages] Failed to load more room:", err);
})
.finally(() => {
setIsLoadingMore(false);
});
}
}
},
[isLoadingMore, currentPage, conversationId, roomId, dispatch],
);
const hasMessages = chatMessages.length > 0;
const isEmpty = !hasMessages && (!isLoading || isKnownEmpty);
return (