set up listener to retrieve messages

fixed listener unsubscriptions in Room.tsx
pull/3/head
Simon Huang 5 years ago
parent 4c5ccc0afb
commit 1cde39461a

@ -1,9 +1,3 @@
ion-grid {
border-left: solid 1px #bbb;
border-right: solid 1px #bbb;
height: 100%;
}
ion-col {
padding: 10px;
border-radius: 10px;
@ -20,6 +14,17 @@ ion-textarea {
justify-content: flex-end;
}
.message-grid {
padding-left: calc(100vw - 100%);
margin-right: 0;
height: 100%;
}
.message-input {
margin-right: 0;
border: solid 1px #bbb;
}
.my-msg {
text-align: right;
background: var(--ion-color-primary);

@ -1,6 +1,6 @@
import { IonButton, IonCol, IonContent, IonFooter, IonGrid, IonRow, IonTextarea } from '@ionic/react';
import React, { useState } from 'react';
import { db, timestamp } from '../services/firebase';
import React, { useEffect, useState } from 'react';
import { currTime, db, timestamp } from '../services/firebase';
import './Chat.css';
type ChatProps = {
@ -8,53 +8,102 @@ type ChatProps = {
userId: string;
};
type Message = {
id: string;
senderId: string;
sender: string;
content: string;
};
const Chat: React.FC<ChatProps> = ({ roomId, userId }) => {
const [message, setMessage] = useState('');
const [room] = useState(roomId);
const [message, setMessage] = useState(''); // Message to be sent
const [prevMessages, setPrevMessages] = useState<Message[]>([]); // Track previous messages for updating useEffect
const [newMessages, setNewMessages] = useState<Message[]>([]); // Newly retrieved messages
const [chats, setChats] = useState<Message[]>([
{ id: '', senderId: userId, sender: '', content: 'You have joined the room.' },
]); // All received messages
const [loading, setLoading] = useState(true);
// Listen for new messages
useEffect(() => {
const chatUnsubscribe = db
.collection('rooms')
.doc(room)
.collection('messages')
.orderBy('createdAt')
.where('createdAt', '>', currTime)
.onSnapshot(async (querySnapshot) => {
let newMsgs: Message[] = [];
const changes = querySnapshot.docChanges();
for (const change of changes) {
if (change.type === 'added') {
const data = change.doc.data();
const user = await db.collection('users').doc(data?.senderId).get();
newMsgs.push({
id: change.doc.id,
senderId: data?.senderId,
sender: user.data()?.name,
content: data?.content,
});
}
}
if (newMsgs.length !== 0) {
setNewMessages(newMsgs);
}
});
setLoading(false);
return () => {
chatUnsubscribe();
};
}, [room]);
// Only update array containing all messages when there are new messages
useEffect(() => {
if (prevMessages !== newMessages) {
setPrevMessages(newMessages);
setChats([...chats, ...newMessages]);
}
}, [prevMessages, newMessages, chats]);
// Send message to database and reset textarea field
const sendMessage = async () => {
const messageId = await db.collection('rooms').doc(roomId).collection('messages').add({
await db.collection('rooms').doc(roomId).collection('messages').add({
createdAt: timestamp,
senderId: userId,
content: message,
});
console.log(messageId);
setMessage('');
};
return (
<>
<IonContent>
<IonGrid>
<IonRow class="right-align">
<IonCol size="auto" class="my-msg">
<b>Simon: </b>
<span>Hello!</span>
</IonCol>
</IonRow>
<IonRow>
<IonCol size="auto" class="other-msg">
<b>Manuel: </b>
<span>They are all asking me about what I'm going to do next</span>
</IonCol>
</IonRow>
<IonRow>
<IonCol size="auto" class="other-msg">
<b>Amaria: </b>
<span>Probably riding on</span>
</IonCol>
</IonRow>
<IonRow class="right-align">
<IonCol size="auto" class="my-msg">
<b>Simon: </b>
<span>my photo jet</span>
</IonCol>
</IonRow>
<IonGrid class="message-grid">
{!loading ? (
chats.map((chat) => {
return (
<IonRow key={chat.id} class={chat.senderId === userId ? 'right-align' : ''}>
<IonCol size="auto" class={chat.senderId === userId ? 'my-msg' : 'other-msg'}>
{chat.sender !== '' ? <b>{chat.sender}: </b> : <></>}
<span>{chat.content}</span>
</IonCol>
</IonRow>
);
})
) : (
<></>
)}
</IonGrid>
</IonContent>
<IonFooter class="ion-no-border">
<IonGrid>
<IonGrid class="message-input">
<IonRow>
<IonCol size="9">
<IonTextarea onIonChange={(e) => setMessage(e.detail.value!)}></IonTextarea>
<IonTextarea onIonChange={(e) => setMessage(e.detail.value!)} value={message}></IonTextarea>
</IonCol>
<IonCol size="3" class="send-msg">
<IonButton expand="block" color="primary" onClick={sendMessage} class="send-button">

@ -13,7 +13,6 @@ const Room: React.FC<RouteComponentProps<{ roomId: string }>> = ({ match }) => {
const [userId, setUserId] = useState('');
const [loading, setLoading] = useState(true);
const [userCount, setUserCount] = useState(0);
const [didConnect, setDidConnect] = useState(false);
// Verify that the roomId exists in db
useEffect(() => {
@ -49,7 +48,7 @@ const Room: React.FC<RouteComponentProps<{ roomId: string }>> = ({ match }) => {
// Subscribe listeners
useEffect(() => {
if (!didConnect && userId !== '' && validRoom) {
if (userId !== '' && validRoom) {
const populateRoom = () => {
const roomRef = rtdb.ref('/rooms/' + roomId);
const availableRef = rtdb.ref('/available/');
@ -68,7 +67,7 @@ const Room: React.FC<RouteComponentProps<{ roomId: string }>> = ({ match }) => {
});
// Re-add room into /available/ if the room was deleted
availableRef.on('child_removed', async (snapshot) => {
availableRef.on('value', async (snapshot) => {
if (!snapshot.hasChild(roomId)) {
await availableRef.child(roomId).set({
name: 'Room Name',
@ -77,7 +76,7 @@ const Room: React.FC<RouteComponentProps<{ roomId: string }>> = ({ match }) => {
}
});
setLoading(false); // Ready when connection to rtdb is made
setLoading(false); // Ready when connections to databases are made
// Unsubscribe listeners
return () => {
@ -87,10 +86,13 @@ const Room: React.FC<RouteComponentProps<{ roomId: string }>> = ({ match }) => {
};
};
populateRoom();
setDidConnect(true); // Run this useEffect only once
const unsub = populateRoom();
return () => {
unsub();
};
}
}, [userId, validRoom, roomId, userCount, loading, didConnect]);
}, [userId, validRoom, roomId]);
// Handle disconnect events
useEffect(() => {

Loading…
Cancel
Save