projects/deliberation_at_scale/packages/frontend/components/RoomChatMessages.tsx (60 lines of code) (raw):
'use client';
import useRoom from "@/hooks/useRoom";
import ChatMessageList from "./ChatMessageList";
import ChatInput from "./ChatInput";
import { useCallback, useEffect } from "react";
import { useSendRoomMessageMutation } from "@/generated/graphql";
import useScrollToBottom from "@/hooks/useScrollToBottom";
import { ONE_SECOND_MS } from "@/utilities/constants";
import { openRoomChat } from "@/state/slices/room";
import { useAppDispatch } from "@/state/store";
import useRoomActions from "@/hooks/useRoomActions";
import ChatActions from "./ChatActions";
import { usePingParticipant } from "@/hooks/usePingParticipant";
export default function RoomChatMessages() {
const { messages, participant, participantId, roomId, messagesLoading, refetchMessages } = useRoom();
const { actions } = useRoomActions();
const [sendRoomMessage, { loading: isSendingMessage }] = useSendRoomMessageMutation();
const dispatch = useAppDispatch();
const chatInputDisabled = isSendingMessage;
const sendMessage = useCallback(async (content: string) => {
const formattedMessage = content?.trim?.();
if (isSendingMessage) {
return false;
}
await sendRoomMessage({
variables: {
content: formattedMessage,
participantId,
roomId,
}
});
// TMP: temporary until Realtime has better performance
refetchMessages();
return true;
}, [isSendingMessage, sendRoomMessage, participantId, roomId, refetchMessages]);
// automatically scroll the messages container to the bottom on new messages
const { scrollToBottom } = useScrollToBottom({ data: messages });
// instantly scroll to the bottom when the messages are loaded
useEffect(() => {
if (!messagesLoading) {
setTimeout(() => {
scrollToBottom('instant');
}, ONE_SECOND_MS * 0.05);
}
}, [messagesLoading, scrollToBottom]);
// keep track of when this component was shown for the last time
useEffect(() => {
dispatch(openRoomChat());
}, [dispatch]);
// ping the participant entry to know which participants are still in the room
usePingParticipant(participant);
return (
<div className="flex flex-col shrink gap-2 min-h-0 pb-2 px-2 md:px-4 grow relative bottom-0 justify-end">
<ChatMessageList messages={messages} />
<ChatActions actions={actions} />
<ChatInput
onSubmit={async (input) => {
return sendMessage(input.content);
}}
disabled={chatInputDisabled}
helpAvailable={true}
/>
</div>
);
}