diff --git a/schema.ts b/schema.ts index 2fb660b..ed5c477 100644 --- a/schema.ts +++ b/schema.ts @@ -8,19 +8,6 @@ // Firestore const collection = { - chats: [ - { - roomId: { - messages: [ - { - content: 'Message content', - createdAt: 'timestamp', - senderId: 'userId', - }, - ], - }, - }, - ], playlists: [ { roomId: { @@ -71,6 +58,17 @@ const turtle = { }, }, + // Keep chats in Realtime DB could potentially lower cost + chats: { + roomId: { + messageId: { + content: 'Message content', + senderId: 'userId', + createdAt: 'timestamp', + }, + }, + }, + // Keeping track of which users are present in a room rooms: { roomId: { diff --git a/src/components/Chatbox.tsx b/src/components/Chatbox.tsx index a934e23..4adcc97 100644 --- a/src/components/Chatbox.tsx +++ b/src/components/Chatbox.tsx @@ -1,7 +1,7 @@ import { IonCard, IonFabButton, IonFooter, IonIcon, IonInput, IonToolbar } from '@ionic/react'; import { sendOutline } from 'ionicons/icons'; import React, { useState } from 'react'; -import { db, arrayUnion } from '../services/firebase'; +import { rtdb } from '../services/firebase'; import './Chatbox.css'; import Messages from './Messages'; import OnlineList from './OnlineList'; @@ -19,16 +19,11 @@ const Chat: React.FC = ({ ownerId, roomId, userId, userList }) => // Send message to database const sendMessage = async () => { if (message !== '') { - await db - .collection('chats') - .doc(roomId) - .update({ - messages: arrayUnion({ - createdAt: Date.now(), - senderId: userId, - content: message, - }), - }); + await rtdb.ref('/chats/' + roomId).push({ + content: message, + createdAt: Date.now(), + senderId: userId, + }); // Reset textarea field setMessage(''); diff --git a/src/components/Messages.tsx b/src/components/Messages.tsx index 961e5bc..4192736 100644 --- a/src/components/Messages.tsx +++ b/src/components/Messages.tsx @@ -1,6 +1,6 @@ import { IonCol, IonContent, IonGrid, IonRow } from '@ionic/react'; import React, { useEffect, useRef, useState } from 'react'; -import { db, arrayUnion } from '../services/firebase'; +import { db, arrayUnion, rtdb } from '../services/firebase'; import './Messages.css'; import { secondsToTimestamp } from '../services/utilities'; @@ -37,31 +37,22 @@ const Messages: React.FC = ({ ownerId, roomId, userId, userList } // Listen for new chat messages useEffect(() => { - const chatUnsubscribe = db - .collection('chats') - .doc(roomId) - .onSnapshot((docSnapshot) => { - const data = docSnapshot.data(); - if (data !== undefined) { - const messages = data.messages; - - let arr: Message[] = []; - for (const msg of messages) { - if (msg.createdAt > joinTime) { - arr.push({ - content: msg.content, - createdAt: msg.createdAt, - id: msg.senderId + msg.createdAt, - senderId: msg.senderId, - }); - } - } - setChats(arr); - } + rtdb.ref('/chats/' + roomId).on('value', (snapshot) => { + let arr: Message[] = []; + snapshot.forEach((child) => { + const msg = child.val(); + arr.push({ + content: msg.content, + createdAt: msg.createdAt, + id: msg.senderId + msg.createdAt, + senderId: msg.senderId, + }); }); + setChats(arr); + }); return () => { - chatUnsubscribe(); + rtdb.ref('/chats/' + roomId).off('value'); }; }, [roomId, joinTime]); @@ -142,22 +133,24 @@ const Messages: React.FC = ({ ownerId, roomId, userId, userList } return name; }; + const renderMessages = () => { + return allMessages + .sort((msg1, msg2) => msg1.createdAt - msg2.createdAt) + .map((msg) => { + return ( + + + {getName(msg.senderId) !== '' ? {getName(msg.senderId)}: : <>} + {msg.content} + + + ); + }); + }; + return ( - - {allMessages - .sort((msg1, msg2) => msg1.createdAt - msg2.createdAt) - .map((msg) => { - return ( - - - {getName(msg.senderId) !== '' ? {getName(msg.senderId)}: : <>} - {msg.content} - - - ); - })} - + {userList.size === 0 ? Loading... : renderMessages()} ); }; diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index f5f35f0..ad92908 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -20,9 +20,6 @@ const Home: React.FC = () => { requests: [], state: { time: 0, isPlaying: false }, }); - await db.collection('chats').doc(roomId.id).set({ - messages: [], - }); await db.collection('playlists').doc(roomId.id).set({ createdAt: timestamp, url: 'https://www.youtube.com/watch?v=XEfDYMngJeE', @@ -35,6 +32,7 @@ const Home: React.FC = () => { // RealTimeDB preparations await rtdb.ref('/rooms/' + roomId.id).set({ userCount: 0 }); await rtdb.ref('/available/' + roomId.id).set({ name: 'Room Name', createdAt: new Date().toISOString() }); + await rtdb.ref('/chats/' + roomId.id).set({ content: 'created a room.', createdAt: Date.now(), senderId: userId }); const path = '/room/' + roomId.id; return history.push(path); diff --git a/src/pages/Room.tsx b/src/pages/Room.tsx index 82555c6..c65a18e 100644 --- a/src/pages/Room.tsx +++ b/src/pages/Room.tsx @@ -114,10 +114,11 @@ const Room: React.FC> = ({ match }) => { // Handle disconnect events useEffect(() => { if (!loading && userId !== '' && validRoom) { - const depopulateRoom = async () => { + const depopulate = async () => { const refUser = rtdb.ref('/rooms/' + roomId + '/' + userId); const refRoom = rtdb.ref('/rooms/' + roomId); const refAvailable = rtdb.ref('/available/' + roomId); + const refChat = rtdb.ref('/chats/' + roomId); // Always remove user from room on disconnect await refRoom.onDisconnect().update({ userCount: decrement }); @@ -127,15 +128,17 @@ const Room: React.FC> = ({ match }) => { if (userCount <= 1) { await refRoom.onDisconnect().remove(); await refAvailable.onDisconnect().remove(); + await refChat.onDisconnect().remove(); } else { - await refRoom.onDisconnect().cancel(); // Cancels all disconnect actions at and under refRoom + await refRoom.onDisconnect().cancel(); // Cancel all disconnect actions await refAvailable.onDisconnect().cancel(); + await refChat.onDisconnect().cancel(); await refRoom.onDisconnect().update({ userCount: decrement }); // User disconnect still needs to be handled await refUser.onDisconnect().remove(); } }; - depopulateRoom(); + depopulate(); } }, [userId, validRoom, roomId, loading, userCount]);