Firebase Optimization #93
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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,16 @@ 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)
|
||||
if (!doneLoading) {
|
||||
setDoneLoading(true)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
|
||||
@@ -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,13 @@ 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)
|
||||
if (!doneLoading) {
|
||||
setDoneLoading(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
@@ -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(
|
||||
<SystemMessage
|
||||
chatObj={messages[message]}
|
||||
key={messages[message].timestamp}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
chatsArr.push(
|
||||
<Chat
|
||||
chatObj={messages[message]}
|
||||
user={user}
|
||||
path={"/dms/" + roomObj.room}
|
||||
key={messages[message].timestamp}
|
||||
/>
|
||||
);
|
||||
// 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(
|
||||
<SystemMessage
|
||||
chatObj={messages[message]}
|
||||
key={messages[message].timestamp}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
chatsArr.push(
|
||||
<Chat
|
||||
chatObj={messages[message]}
|
||||
user={user}
|
||||
path={"/dms/" + chatRoomObj.room}
|
||||
key={messages[message].timestamp}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
);
|
||||
|
||||
@@ -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}`))
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 (
|
||||
<div className="hover:bg-[#C0C0C0] rounded-lg">
|
||||
<div className="hover:bg-[#C0C0C0] rounded-lg cursor-pointer" >
|
||||
<div className="float-right top-0 cursor-pointer p-2 text-[24px] text-slate-500">
|
||||
<div onClick={() => {removeNotification(data.id)}}><CloseIcon/></div>
|
||||
<div onClick={() => {removeNotification()}}><CloseIcon/></div>
|
||||
</div>
|
||||
<div className="p-3 text-left">
|
||||
{data.title}<br/>
|
||||
<div className="p-3 text-left" onClick={() => {onClick()}}>
|
||||
<span className="font-bold">{data.title}</span><br/>
|
||||
{data.byline}<br/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(<Notification data={user.notification[notificationPackage]}/>)
|
||||
if (user.notifications) {
|
||||
for (var notificationPackage in user.notifications) {
|
||||
notificationsMap.push(<Notification data={user.notifications[notificationPackage]}/>)
|
||||
}
|
||||
} else {
|
||||
notificationsMap = null
|
||||
}
|
||||
var isNotifications = true
|
||||
} else {
|
||||
var isNotifications = false
|
||||
}
|
||||
|
||||
return (
|
||||
<Popover className="relative">
|
||||
@@ -88,8 +99,8 @@ export function NotificationPanel({user}) {
|
||||
|
||||
<Popover.Panel className="absolute z-10 bg-white mt-[4px] rounded-xl ml-3 shadow-2xl w-64 md:right-[0px] max-md:right-[-300%]">
|
||||
<div className="grid grid-cols-1">
|
||||
{isNotifications && notificationsMap}
|
||||
{!isNotifications &&
|
||||
{notificationsMap}
|
||||
{!notificationsMap &&
|
||||
<div className="h-[64px] flex flex-col justify-center items-center">
|
||||
<NotificationsPausedIcon/> All caught up!
|
||||
</div>
|
||||
|
||||
@@ -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(
|
||||
<SystemMessage
|
||||
chatObj={messages[message]}
|
||||
key={messages[message].timestamp}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
chatsArr.push(
|
||||
<Chat
|
||||
chatObj={messages[message]}
|
||||
user={user}
|
||||
path={"/rooms/" +roomObj.path + "/" + roomObj.name + "-" + roomObj.timestamp}
|
||||
key={messages[message].timestamp}
|
||||
/>
|
||||
);
|
||||
});
|
||||
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(
|
||||
<SystemMessage
|
||||
chatObj={messages[message]}
|
||||
key={messages[message].timestamp}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
chatsArr.push(
|
||||
<Chat
|
||||
chatObj={messages[message]}
|
||||
user={user}
|
||||
path={"/rooms/" + chatRoomObj.path + "/" + chatRoomObj.name + "-" + chatRoomObj.timestamp}
|
||||
key={messages[message].timestamp}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
var chats = chatsArr.reverse();
|
||||
|
||||
setChats(chatsArr.reverse())
|
||||
}, [chatRoomObj])
|
||||
|
||||
/**
|
||||
* Send Message in Chatroom
|
||||
* @param {JSON} data - Message data to send (from form)
|
||||
@@ -63,9 +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
|
||||
);
|
||||
|
||||
@@ -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(<Member memberObj={activeUsersJSON[activeUser]} />);
|
||||
var chatroomOnline = activeUsers
|
||||
activeUsers.push(<Member memberObj={activeUsersJSON[activeUser]} key={activeUser} />);
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (user) {
|
||||
@@ -49,7 +49,7 @@ export function Sidebar({user, chatRoomObj}) {
|
||||
</div>
|
||||
<div className="bg-white rounded-lg m-2 shadow-2xl">
|
||||
<div>In The Chat</div>
|
||||
{chatroomOnline}
|
||||
{activeUsers}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user