From 3af8e3bb6d08c024f1285c8435f6866ac0dce054 Mon Sep 17 00:00:00 2001 From: Nicholas Pease Date: Sat, 20 Apr 2024 23:42:44 -0400 Subject: [PATCH 1/2] Firebase Optimization --- frontend-next/src/app/chat/page.js | 26 +++++++++++++-- frontend-next/src/app/dm/page.js | 32 +++++++++++++++---- frontend-next/src/components/app/page/chat.js | 4 +-- 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/frontend-next/src/app/chat/page.js b/frontend-next/src/app/chat/page.js index 3fed1f1..80df277 100644 --- a/frontend-next/src/app/chat/page.js +++ b/frontend-next/src/app/chat/page.js @@ -5,7 +5,7 @@ import { useState, useEffect } from "react"; // Firebase Imports import { auth, database } from "../../../firebase-config"; -import { ref, onValue, set, onDisconnect } from "firebase/database"; +import { ref, onValue, set, onDisconnect, get, onChildAdded, onChildRemoved } from "firebase/database"; import { useAuthState } from "react-firebase-hooks/auth" // Component Imports @@ -90,13 +90,35 @@ function Chat() { uid: user.uid, })*/ - onValue(ref(database, `/rooms/${path}`), (roomData) => { + // Room Object Load + get(ref(database, `/rooms/${path}`)).then((roomData) => { roomData = roomData.val(); setChatRoomObj(roomData) + onChildAdded(ref(database, `/rooms/${path}/chats`), (newChat) => { + var newChatRoomObj = chatRoomObj + if (newChatRoomObj) { + if (!newChatRoomObj.chats) { + newChatRoomObj.chats = {} + } + newChatRoomObj.chats[newChat.key] = newChat.val() + setChatRoomObj({...newChatRoomObj}) + } + + }); + onChildRemoved(ref(database, `/rooms/${path}/chats`), (removed) => { + if (chatRoomObj) { + var newChatRoomObj = chatRoomObj + var deleted = removed.val() + delete newChatRoomObj.chats[`${deleted.timestamp}-${deleted.user}`] + setChatRoomObj({...newChatRoomObj}) + } + }); if (!doneLoading) { setDoneLoading(true) } }) + + } }, [user]); diff --git a/frontend-next/src/app/dm/page.js b/frontend-next/src/app/dm/page.js index b46a1fb..a55486d 100644 --- a/frontend-next/src/app/dm/page.js +++ b/frontend-next/src/app/dm/page.js @@ -5,7 +5,7 @@ import { useState, useEffect } from "react"; // Firebase Imports import { auth, database } from "../../../firebase-config"; -import { ref, onValue, set, onDisconnect } from "firebase/database"; +import { ref, onValue, set, onDisconnect, get, onChildAdded, onChildRemoved } from "firebase/database"; import { useAuthState } from "react-firebase-hooks/auth" // Component Imports @@ -94,12 +94,32 @@ function Chat() { uid: user.uid, })*/ - onValue(ref(database, `/dms/${path}`), (roomData) => { - roomData = roomData.val(); - setChatRoomObj(roomData) - if (!doneLoading) { - setDoneLoading(true) + // Room Object Load + get(ref(database, `/dms/${path}`)).then((roomData) => { + roomData = roomData.val(); + setChatRoomObj(roomData) + onChildAdded(ref(database, `/dms/${path}/chats`), (newDM) => { + var newDMRoomObj = chatRoomObj + if (newDMRoomObj) { + if (!newDMRoomObj.chats) { + newDMRoomObj.chats = {} + } + newDMRoomObj.chats[newDM.key] = newDM.val() + setChatRoomObj({...newDMRoomObj}) } + + }); + onChildRemoved(ref(database, `/dms/${path}/chats`), (removed) => { + if (chatRoomObj) { + var newDMRoomObj = chatRoomObj + var deleted = removed.val() + delete newDMRoomObj.chats[`${deleted.timestamp}-${deleted.user}`] + setChatRoomObj({...newDMRoomObj}) + } + }); + if (!doneLoading) { + setDoneLoading(true) + } }) } }, [user]); diff --git a/frontend-next/src/components/app/page/chat.js b/frontend-next/src/components/app/page/chat.js index 4df9604..e98b330 100644 --- a/frontend-next/src/components/app/page/chat.js +++ b/frontend-next/src/components/app/page/chat.js @@ -63,9 +63,7 @@ export function ChatRoom({ roomObj, user }) { set( ref( database, - `/rooms/${ - roomObj.path + "/" + roomObj.name + "-" + roomObj.timestamp - }/chats/${new Date().getTime()}-${user.username}` + `/rooms/${roomObj.path + "/" + roomObj.name + "-" + roomObj.timestamp}/chats/${new Date().getTime()}-${user.username}` ), payload ); -- 2.52.0 From 3d85f9770e3d0ae9ec86504cfcd3abc4bd15dd95 Mon Sep 17 00:00:00 2001 From: Nicholas Pease Date: Sun, 21 Apr 2024 02:04:56 -0400 Subject: [PATCH 2/2] Proper Optimization --- frontend-next/src/app/app/page.js | 2 +- frontend-next/src/app/chat/page.js | 19 ---- frontend-next/src/app/dm/page.js | 21 +--- .../src/components/app/friends/page.js | 98 ++++++++++++++----- frontend-next/src/components/app/header.js | 1 + .../app/notifications/notifications.js | 61 +++++++----- frontend-next/src/components/app/page/chat.js | 79 ++++++++++----- .../src/components/app/sidebar/dm.js | 24 ++--- 8 files changed, 179 insertions(+), 126 deletions(-) diff --git a/frontend-next/src/app/app/page.js b/frontend-next/src/app/app/page.js index b45788a..b35b67d 100644 --- a/frontend-next/src/app/app/page.js +++ b/frontend-next/src/app/app/page.js @@ -46,7 +46,7 @@ function Home() { onValue(ref(database, `users/${authUser.uid}`), (userData) => { userData = userData.val(); if (userData) { - setUser(userData); + setUser({...userData}); } else { window.location.href = "/onboarding"; } diff --git a/frontend-next/src/app/chat/page.js b/frontend-next/src/app/chat/page.js index 80df277..37a37d6 100644 --- a/frontend-next/src/app/chat/page.js +++ b/frontend-next/src/app/chat/page.js @@ -94,25 +94,6 @@ function Chat() { get(ref(database, `/rooms/${path}`)).then((roomData) => { roomData = roomData.val(); setChatRoomObj(roomData) - onChildAdded(ref(database, `/rooms/${path}/chats`), (newChat) => { - var newChatRoomObj = chatRoomObj - if (newChatRoomObj) { - if (!newChatRoomObj.chats) { - newChatRoomObj.chats = {} - } - newChatRoomObj.chats[newChat.key] = newChat.val() - setChatRoomObj({...newChatRoomObj}) - } - - }); - onChildRemoved(ref(database, `/rooms/${path}/chats`), (removed) => { - if (chatRoomObj) { - var newChatRoomObj = chatRoomObj - var deleted = removed.val() - delete newChatRoomObj.chats[`${deleted.timestamp}-${deleted.user}`] - setChatRoomObj({...newChatRoomObj}) - } - }); if (!doneLoading) { setDoneLoading(true) } diff --git a/frontend-next/src/app/dm/page.js b/frontend-next/src/app/dm/page.js index a55486d..815da34 100644 --- a/frontend-next/src/app/dm/page.js +++ b/frontend-next/src/app/dm/page.js @@ -5,7 +5,7 @@ import { useState, useEffect } from "react"; // Firebase Imports import { auth, database } from "../../../firebase-config"; -import { ref, onValue, set, onDisconnect, get, onChildAdded, onChildRemoved } from "firebase/database"; +import { ref, onValue, set, onDisconnect, get, onChildAdded, onChildRemoved} from "firebase/database"; import { useAuthState } from "react-firebase-hooks/auth" // Component Imports @@ -98,25 +98,6 @@ function Chat() { get(ref(database, `/dms/${path}`)).then((roomData) => { roomData = roomData.val(); setChatRoomObj(roomData) - onChildAdded(ref(database, `/dms/${path}/chats`), (newDM) => { - var newDMRoomObj = chatRoomObj - if (newDMRoomObj) { - if (!newDMRoomObj.chats) { - newDMRoomObj.chats = {} - } - newDMRoomObj.chats[newDM.key] = newDM.val() - setChatRoomObj({...newDMRoomObj}) - } - - }); - onChildRemoved(ref(database, `/dms/${path}/chats`), (removed) => { - if (chatRoomObj) { - var newDMRoomObj = chatRoomObj - var deleted = removed.val() - delete newDMRoomObj.chats[`${deleted.timestamp}-${deleted.user}`] - setChatRoomObj({...newDMRoomObj}) - } - }); if (!doneLoading) { setDoneLoading(true) } diff --git a/frontend-next/src/components/app/friends/page.js b/frontend-next/src/components/app/friends/page.js index 2d6e84b..3d953c7 100644 --- a/frontend-next/src/components/app/friends/page.js +++ b/frontend-next/src/components/app/friends/page.js @@ -2,7 +2,7 @@ import { Form, useForm } from "react-hook-form"; // Firebase Imports -import { ref, set } from "firebase/database"; +import { ref, set, onChildAdded, onChildRemoved } from "firebase/database"; import { database } from "../../../../firebase-config"; // Component Imports @@ -11,6 +11,11 @@ import { Chat, SystemMessage } from "../datatypes"; // Icons import SendIcon from '@mui/icons-material/Send'; +// Notification +import { createNotification } from "../notifications/notifications"; + +import { useEffect, useState } from "react"; + /** * Chat Room Component * @prop {JSON} roomObj - Room Object @@ -18,31 +23,61 @@ import SendIcon from '@mui/icons-material/Send'; * @returns {Object} - Chat Room Component */ export function DMRoom({ roomObj, user }) { + const [chatRoomObj, setChatRoomObj] = useState(roomObj); + const [chats, setChats] = useState(null); var { register, control, reset, handleSubmit } = useForm(); - // Message updater - var chatsArr = []; - var messages = roomObj.chats; - for (var message in messages) { - if (messages[message].isSystem) { - chatsArr.push( - - ); - } else { - chatsArr.push( - - ); + // Listeners for DMs + useEffect(() => { + var path = roomObj.UIDs[0] < roomObj.UIDs[1] ? roomObj.UIDs[0] + "-" + roomObj.UIDs[1] : roomObj.UIDs[1] + "-" + roomObj.UIDs[0]; + onChildAdded(ref(database, `/dms/${path}/chats`), (newDM) => { + if (chatRoomObj) { + var newDMRoomObj = chatRoomObj + if (newDMRoomObj) { + if (!newDMRoomObj.chats) { + newDMRoomObj.chats = {} + } + newDMRoomObj.chats[newDM.key] = newDM.val() + setChatRoomObj({...newDMRoomObj}) + } + } + + }); + onChildRemoved(ref(database, `/dms/${path}/chats`), (removed) => { + if (chatRoomObj) { + var newDMRoomObj = chatRoomObj + var deleted = removed.val() + delete newDMRoomObj.chats[`${deleted.timestamp}-${deleted.user}`] + setChatRoomObj({...newDMRoomObj}) + } + }); + }, []) + + useEffect(() => { + // Message updater + var chatsArr = []; + var messages = chatRoomObj.chats; + for (var message in messages) { + if (messages[message].isSystem) { + chatsArr.push( + + ); + } else { + chatsArr.push( + + ); + } } - } - var chats = chatsArr.reverse(); + setChats(chatsArr.reverse()) + }, [chatRoomObj]) /** * Send Message in Chatroom @@ -50,6 +85,21 @@ export function DMRoom({ roomObj, user }) { * @returns {void} */ function sendMessage(data) { + // Other UID + var otherUID = chatRoomObj.initUID == user.uid ? chatRoomObj.targetUID : chatRoomObj.initUID; + // Send other user notification if not in room + if (chatRoomObj.users && chatRoomObj.users.online) { + if (!(otherUID in chatRoomObj.users.online)) { + createNotification( + "New Message", + `${user.username} sent you a message.`, + "dm", + user.uid, + otherUID + ); + } + } + var messageFilterBypass = [undefined, null, "", " ", ' ', '\''] reset(); if (!messageFilterBypass.includes(data.message)) { @@ -63,7 +113,7 @@ export function DMRoom({ roomObj, user }) { set( ref( database, - `/dms/${roomObj.room}/chats/${new Date().getTime()}-${user.username}` + `/dms/${chatRoomObj.room}/chats/${new Date().getTime()}-${user.username}` ), payload ); diff --git a/frontend-next/src/components/app/header.js b/frontend-next/src/components/app/header.js index 467f89d..42d82eb 100644 --- a/frontend-next/src/components/app/header.js +++ b/frontend-next/src/components/app/header.js @@ -23,6 +23,7 @@ import CloseIcon from '@mui/icons-material/Close'; */ function closeChat(chatRoomObj, user) { remove(ref(database, `/rooms/${chatRoomObj.path}/${chatRoomObj.name}-${chatRoomObj.timestamp}/users/online/${user.uid}`)) + } /** diff --git a/frontend-next/src/components/app/notifications/notifications.js b/frontend-next/src/components/app/notifications/notifications.js index b6dc474..9294ea9 100644 --- a/frontend-next/src/components/app/notifications/notifications.js +++ b/frontend-next/src/components/app/notifications/notifications.js @@ -17,28 +17,38 @@ import { ref, set, remove } from "firebase/database"; * @returns {Notification} - Notification Component */ function Notification({data}) { + /** + * Removes Notification + * @returns {void} + */ + function removeNotification() { + remove(ref(database, `/users/${data.ruser}/notifications/${data.suser}-${data.action}`)) + } + + /** + * Determines Action + */ + function onClick() { + if (data.action === "dm") { + var order = data.suser > data.ruser ? data.ruser + "-" + data.suser : data.suser + "-" + data.ruser; + window.location.href = "/dm?dm=" + order; + removeNotification() + } + } + return ( -
+
-
{removeNotification(data.id)}}>
+
{removeNotification()}}>
-
- {data.title}
+
{onClick()}}> + {data.title}
{data.byline}
) } -/** - * Removes Notification - * @param {String} ruser - Receiving user UID (User Whose Notifications are being removed) - * @param {String} dataID - Notification ID - * @returns {void} - */ -function removeNotification(ruser, dataID) { - remove(ref(database, `/user/${ruser}/notifications/${dataID}`)) -} /** * Creates New Notification @@ -49,16 +59,18 @@ function removeNotification(ruser, dataID) { * @param {String} ruser - Receiving user UID * @returns {void} */ -function createNotification(title, byline, action, suser, ruser) { +export function createNotification(title, byline, action, suser, ruser) { var timestamp = new Date().getTime(); var payload = { title: title, byline: byline, action: action, suser: suser, - ruser: ruser + ruser: ruser, + id: suser + "-" + action, + timestamp: timestamp }; - set(ref(database, `/user/${ruser}/notifications/${timestamp}-${suser}`), payload); + set(ref(database, `/users/${ruser}/notifications/${suser}-${action}`), payload); } /** @@ -69,14 +81,13 @@ function createNotification(title, byline, action, suser, ruser) { */ export function NotificationPanel({user}) { var notificationsMap = [] - if (user.notification) { - for (var notificationPackage in user.notification) { - notificationsMap.push() + if (user.notifications) { + for (var notificationPackage in user.notifications) { + notificationsMap.push() + } + } else { + notificationsMap = null } - var isNotifications = true - } else { - var isNotifications = false - } return ( @@ -88,8 +99,8 @@ export function NotificationPanel({user}) {
- {isNotifications && notificationsMap} - {!isNotifications && + {notificationsMap} + {!notificationsMap &&
All caught up!
diff --git a/frontend-next/src/components/app/page/chat.js b/frontend-next/src/components/app/page/chat.js index e98b330..11ab617 100644 --- a/frontend-next/src/components/app/page/chat.js +++ b/frontend-next/src/components/app/page/chat.js @@ -2,7 +2,7 @@ import { Form, useForm } from "react-hook-form"; // Firebase Imports -import { ref, set } from "firebase/database"; +import { ref, set, onChildAdded, onChildRemoved } from "firebase/database"; import { database } from "../../../../firebase-config"; // Component Imports @@ -10,6 +10,7 @@ import { Chat, SystemMessage } from "../datatypes"; // Icons import SendIcon from '@mui/icons-material/Send'; +import { useState,useEffect } from "react"; /** * Chat Room Component @@ -18,32 +19,60 @@ import SendIcon from '@mui/icons-material/Send'; * @returns {Object} - Chat Room Component */ export function ChatRoom({ roomObj, user }) { + const [chatRoomObj, setChatRoomObj] = useState(roomObj); + const [chats, setChats] = useState(null); var { register, control, reset, handleSubmit } = useForm(); + + // Listeners for Chats + useEffect(() => { + var path = chatRoomObj.path + "/" + chatRoomObj.name + "-" + chatRoomObj.timestamp; + onChildAdded(ref(database, `/rooms/${path}/chats`), (newChat) => { + var newChatRoomObj = chatRoomObj + if (newChatRoomObj) { + if (!newChatRoomObj.chats) { + newChatRoomObj.chats = {} + } + newChatRoomObj.chats[newChat.key] = newChat.val() + setChatRoomObj({...newChatRoomObj}) + } - // Message updater - var chatsArr = []; - var messages = roomObj.chats; - for (var message in messages) { - if (messages[message].isSystem) { - chatsArr.push( - - ); - } else { - chatsArr.push( - - ); + }); + onChildRemoved(ref(database, `/rooms/${path}/chats`), (removed) => { + if (chatRoomObj) { + var newChatRoomObj = chatRoomObj + var deleted = removed.val() + delete newChatRoomObj.chats[`${deleted.timestamp}-${deleted.user}`] + setChatRoomObj({...newChatRoomObj}) + } + }); + }, []) + + useEffect(() => { + // Message updater + var chatsArr = []; + var messages = chatRoomObj.chats; + for (var message in messages) { + if (messages[message].isSystem) { + chatsArr.push( + + ); + } else { + chatsArr.push( + + ); + } } - } - var chats = chatsArr.reverse(); - + setChats(chatsArr.reverse()) + }, [chatRoomObj]) + /** * Send Message in Chatroom * @param {JSON} data - Message data to send (from form) @@ -63,7 +92,7 @@ export function ChatRoom({ roomObj, user }) { set( ref( database, - `/rooms/${roomObj.path + "/" + roomObj.name + "-" + roomObj.timestamp}/chats/${new Date().getTime()}-${user.username}` + `/rooms/${chatRoomObj.path + "/" + chatRoomObj.name + "-" + chatRoomObj.timestamp}/chats/${new Date().getTime()}-${user.username}` ), payload ); diff --git a/frontend-next/src/components/app/sidebar/dm.js b/frontend-next/src/components/app/sidebar/dm.js index 33deaec..09b98c6 100644 --- a/frontend-next/src/components/app/sidebar/dm.js +++ b/frontend-next/src/components/app/sidebar/dm.js @@ -1,23 +1,23 @@ import { Member } from "../datatypes" import { database } from "../../../../firebase-config" -import {ref, get, set} from "firebase/database" +import {ref, get, onValue} from "firebase/database" import { useState, useEffect } from "react" export function Sidebar({user, chatRoomObj}) { - const [profileData, setProfileData] = useState(null) - // Active users list - if ( - chatRoomObj.hasOwnProperty("users") && - chatRoomObj.users.hasOwnProperty("online") - ) { - var activeUsers = []; - var activeUsersJSON = chatRoomObj.users.online; + const [profileData, setProfileData] = useState(null) + const [chatroomOnline, setChatroomOnline] = useState(null) + + var path = chatRoomObj.UIDs[0] < chatRoomObj.UIDs[1] ? chatRoomObj.UIDs[0] + "-" + chatRoomObj.UIDs[1] : chatRoomObj.UIDs[1] + "-" + chatRoomObj.UIDs[0]; + var activeUsers = [] + onValue(ref(database, `/dms/${path}/users/online`), (snapshot) => { + if (snapshot.exists()) { + var activeUsersJSON = snapshot.val(); for (var activeUser in activeUsersJSON) - activeUsers.push(); - var chatroomOnline = activeUsers + activeUsers.push(); } + }) useEffect(() => { if (user) { @@ -49,7 +49,7 @@ export function Sidebar({user, chatRoomObj}) {
In The Chat
- {chatroomOnline} + {activeUsers}
-- 2.52.0