Skip to content

Instantly share code, notes, and snippets.

@dejanvasic85
Last active January 8, 2021 11:37
Show Gist options
  • Save dejanvasic85/52eaaa2712d64b670149af24580dd7ee to your computer and use it in GitHub Desktop.
Save dejanvasic85/52eaaa2712d64b670149af24580dd7ee to your computer and use it in GitHub Desktop.
Chat.tsx
import React, { Fragment, useEffect, useRef } from 'react';
import { useQuery, useMutation } from '@apollo/client';
import { List, Typography } from 'antd';
import PageLoader from '../PageLoader/PageLoader';
import ChatInput from './components/ChatInput';
import ChatComment from './components/ChatComment';
import { ADD_MESSAGE, CHAT_ROOM, COMMENTS_SUBSCRIPTION } from './Chat.graphql';
import { AddResponse, ChatRequest, ChatResponse, MessageInput, NewMessage, Props } from './Chat.types';
import styles from './Chat.less';
const Chat = ({ chatRoomId }: Props) => {
const { data: chatData, loading: chatLoading, subscribeToMore } = useQuery<ChatResponse, ChatRequest>(CHAT_ROOM, {
variables: { chatRoomId },
});
const [addMessage, { loading: addMsgLoading }] = useMutation<AddResponse, MessageInput>(ADD_MESSAGE);
const anchorRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const unsubscribe = subscribeToMore<NewMessage>({
document: COMMENTS_SUBSCRIPTION,
variables: {
chatRoomId,
},
updateQuery: (prev: ChatResponse, { subscriptionData }): ChatResponse => {
if (!subscriptionData.data) return prev;
const msg = subscriptionData.data.chatMessageAdded;
const newItems = [
...prev.chatRoom.messages.items,
{
...msg,
__typename: 'ChatMessage',
},
];
const value = {
...prev,
chatRoom: {
...prev.chatRoom,
messages: {
__typename: 'ChatMessageList',
items: newItems,
pageInfo: prev.chatRoom.messages.pageInfo,
},
},
};
anchorRef.current.scrollIntoView();
return value;
},
});
return () => {
unsubscribe();
};
}, []);
useEffect(() => {
if (anchorRef.current) {
anchorRef.current.scrollIntoView();
}
});
if (chatLoading) {
return <PageLoader />;
}
const {
messages: { items },
} = chatData.chatRoom;
const userMap = chatData.chatRoom.users.reduce((prev, curr) => {
return {
...prev,
[curr.userId]: curr.user,
};
}, {});
const sendComment = async (comment: string): Promise<boolean> => {
const { errors } = await addMessage({
variables: {
input: {
chatRoomId,
message: comment,
},
},
});
return errors ? false : true;
};
return (
<Fragment>
<div className={styles.commentsContainer}>
{items.length === 0 && (
<Typography.Text type="secondary">This is the start of the conversation...</Typography.Text>
)}
<List itemLayout="vertical">
{items.map((m) => (
<ChatComment key={m.id} user={userMap[m.userId]} message={m.message} postedAt={m.createdAt} />
))}
</List>
</div>
<div className={styles.newMsgContainer}>
<ChatInput onSubmit={(value) => sendComment(value)} loading={addMsgLoading} comment={''} />
</div>
<div className={styles.anchor} ref={anchorRef}></div>
</Fragment>
);
};
export default Chat;
export const COMMENTS_SUBSCRIPTION = gql`
subscription ChatMessageAdded($chatRoomId: ID!) {
chatMessageAdded(chatRoomId: $chatRoomId) {
id
userId
message
chatRoomId
createdAt
}
}
`;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment