24 Commits

Author SHA1 Message Date
Nicholas Pease 77c2bf9620 Nearby Room Fix / ChatMaps URL Formatting Fix (#103) 2024-04-24 09:27:28 -04:00
npease 91735beb88 Remove hanging console.log / fix linting issues 2024-04-24 01:35:23 -04:00
npease f02e74bc3a Bugfix - Fix nearby rooms on map 2024-04-24 01:25:40 -04:00
npease c3361e3141 Bugfix - RMF Chatma.ps URL Fix 2024-04-24 00:59:04 -04:00
Nicholas Pease 0cf510e95c Various Bug Fixes and Additions (#102) 2024-04-23 19:48:43 -04:00
npease 754442adfa Bugfix - Key on new Rich chatma.ps messages 2024-04-23 19:39:20 -04:00
npease 833361255b Feature - Add Rich Room URL's 2024-04-23 19:37:24 -04:00
npease 7a231c4e39 Bugfix - Cleanup Silent React Errors 2024-04-23 19:07:10 -04:00
npease 08c88fb59c Linting - Linting Complete 2024-04-23 17:52:21 -04:00
npease 4b5454ddc2 Easter Egg - Add /peter command and framework for future commands / easter eggs / Additional easter eggs (including /snoop) 2024-04-23 17:41:59 -04:00
npease 623de2877e Bugfix - URL / Image Detection and TTS Slur Detection / Blocking 2024-04-23 17:33:31 -04:00
npease ce6b23ec98 BugFix - Profile Data Updates / Status Fix 2024-04-23 14:01:24 -04:00
Nicholas Pease a83f219c02 Various Interactivity Bug Fixes (#101) 2024-04-23 11:05:17 -04:00
npease 97325623fe Bug Fix - Remove unused Jsdoc dependency (Breaks Deployment Actions) 2024-04-23 00:53:06 -04:00
npease 19466dd98f Bug Fix - Fix DM Online Not Removing On Close, Fix Onboarded Users Unable to Selectively Edit Profile Fields, Fix DM Online User Updates 2024-04-23 00:46:29 -04:00
npease 577dddd785 Bug Fix - Readd Updating Friend / Friend Requests 2024-04-23 00:17:37 -04:00
npease a58579e753 Bug Fix - Room Live Updates, Initial Account PFP, Initial Account Online Status 2024-04-23 00:07:33 -04:00
npease f5f4706123 Bug Fix - Remove Persistent Online from Added Members in Rooms 2024-04-22 23:38:05 -04:00
Nicholas Pease 0886b85847 TTS Fix (#100) 2024-04-22 20:37:10 -04:00
npease 30a40bf6b1 TTS Fix 2024-04-22 20:35:37 -04:00
Nicholas Pease ae927dea0d Add /tts (#99) 2024-04-22 20:26:47 -04:00
npease 69d2b98d50 Add /tts 2024-04-22 00:51:56 -04:00
Nicholas Pease ceaabd3514 Fixes Across the Board (#98) 2024-04-21 22:50:29 -04:00
npease 94513bb0d9 Fixes Across the Board 2024-04-21 22:49:23 -04:00
28 changed files with 3565 additions and 1799 deletions
-27
View File
@@ -1,27 +0,0 @@
name: JSDoc to GH Pages
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Build
uses: andstor/jsdoc-action@v1
with:
source_dir: ./frontend-next
output_dir: ./jsdoc
recurse: true
template: minami
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./jsdoc
+2 -1
View File
@@ -4,6 +4,7 @@
"no-unused-vars": ["warn", { "vars": "all", "args": "after-used", "ignoreRestSiblings": false }],
"jsx-a11y/alt-text": "off",
"@next/next/no-img-element": "off",
"no-console": 1
"no-console": 1,
"react-hooks/exhaustive-deps": "off"
}
}
+3304 -1525
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -30,7 +30,8 @@
"react-dom": "^18.2.0",
"react-firebase-hooks": "^5.1.1",
"react-hook-form": "^7.50.1",
"react-test-renderer": "^18.2.0"
"react-test-renderer": "^18.2.0",
"tts-react": "^3.0.6"
},
"devDependencies": {
"@capacitor/assets": "^3.0.5",
+3 -3
View File
@@ -10,8 +10,8 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
<main className={inter.className}>
{children}
</main>
);
}
+1 -1
View File
@@ -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";
}
+4 -3
View File
@@ -10,8 +10,9 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
<main className={inter.className}>
{children}
</main>
);
}
+4 -4
View File
@@ -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} from "firebase/database";
import { useAuthState } from "react-firebase-hooks/auth"
// Component Imports
@@ -38,8 +38,8 @@ function Chat() {
// Authentication Verification / Redirection if Profile Data not Filled out
useEffect(() => {
if (authUser && authLoading === false) {
onValue(ref(database, `users/${authUser.uid}`), (userData) => {
if (authUser && authLoading === false && !user) {
onValue(ref(database, `users/${authUser.uid}`),(userData) => {
userData = userData.val();
if (userData) {
setUser(userData);
@@ -91,7 +91,7 @@ function Chat() {
})*/
// Room Object Load
get(ref(database, `/rooms/${path}`)).then((roomData) => {
onValue(ref(database, `/rooms/${path}`), (roomData) => {
roomData = roomData.val();
setChatRoomObj(roomData)
if (!doneLoading) {
+4 -3
View File
@@ -10,8 +10,9 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
<main className={inter.className}>
{children}
</main>
);
}
+5 -4
View File
@@ -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} from "firebase/database";
import { useAuthState } from "react-firebase-hooks/auth"
// Component Imports
@@ -58,10 +58,11 @@ function Chat() {
if (user) {
const searchParams = new URLSearchParams(document.location.search);
var path = searchParams.get("dm")
if (path.includes(user.uid))
if (path.includes(user.uid)) {
setIsUserAuthed(true)
else
} else {
location.href = "/app"
}
/*// Send entered message
var payload = {
body: "entered",
@@ -95,7 +96,7 @@ function Chat() {
})*/
// Room Object Load
get(ref(database, `/dms/${path}`)).then((roomData) => {
onValue(ref(database, `/dms/${path}`), (roomData) => {
roomData = roomData.val();
setChatRoomObj(roomData)
if (!doneLoading) {
-1
View File
@@ -15,7 +15,6 @@ button {
border-radius: 5px;
padding: 5px;
margin: 5px;
filter: drop-shadow(0 25px 25px rgb(0 0 0 / 0.15));
}
button:hover {
+3 -3
View File
@@ -10,8 +10,8 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
<main className={inter.className}>
{children}
</main>
);
}
+4 -4
View File
@@ -31,7 +31,7 @@ function Login() {
}
}
).catch((error) => {
if (error = "auth/invalid-credential") {
if (error == "auth/invalid-credential") {
const formError = {
type: "server",
message: "Username or Password Incorrect",
@@ -99,20 +99,20 @@ function Login() {
{(isSubmitting || isSubmitted) && (
<span className="inline-block">
<svg
class="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
className="animate-spin -ml-1 mr-3 h-5 w-5 text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
class="opacity-25"
className="opacity-25"
cx="12"
cy="12"
r="10"
strokeWidth="4"
></circle>
<path
class="opacity-75"
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
+4 -3
View File
@@ -10,8 +10,9 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
<main className={inter.className}>
{children}
</main>
);
}
+20 -22
View File
@@ -6,27 +6,9 @@ import { useRouter } from "next/navigation";
// Firebase Imports
import { ref, set } from "firebase/database";
import { auth, database } from "../../../firebase-config";
import { auth, database, storage } from "../../../firebase-config";
import { onAuthStateChanged } from "firebase/auth";
/**
* Creates user data in Firebase DB
* @param {JSON} data - User data to be stored in Firebase DB ( from form )
* @return {Boolean} - True if user data is stored, False if user data is not stored
*/
function createUser(data) {
onAuthStateChanged(auth, (user) => {
if (user.uid) {
data.uid = user.uid;
data.defined = true;
data.email = user.email;
set(ref(database, `users/${user.uid}`), data);
return true;
} else {
return false;
}
});
}
import { ref as sRef, getDownloadURL } from "firebase/storage";
/**
* Onboarding Page
@@ -37,8 +19,24 @@ function Onboarding() {
var { register, handleSubmit } = useForm();
function Onboard(data) {
createUser(data);
router.push("/app");
onAuthStateChanged(auth, (user) => {
if (user.uid) {
data.uid = user.uid;
data.defined = true;
data.invisibleStatus = false;
data.bio = " ";
data.interests = " , , "
getDownloadURL(sRef(storage, `/default.png`)).then((url) => {
data.pfp = url;
data.email = user.email;
set(ref(database, `users/${user.uid}`), data);
router.push("/app");
})
} else {
return false;
}
});
}
return (
<div>
+3 -3
View File
@@ -46,9 +46,9 @@ function Home() {
get(ref(database, `/rooms/${path}`)).then((snapshot) => {
if (snapshot.exists()) {
var count = 0;
for (var room in snapshot.val()) {
count += 1;
}
snapshot.forEach(() => {
count++;
});
setRoomCount(count);
} else {
setRoomCount(0);
+3 -3
View File
@@ -10,8 +10,8 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
<main className={inter.className}>
{children}
</main>
);
}
+3 -3
View File
@@ -10,8 +10,8 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
<main className={inter.className}>
{children}
</main>
);
}
+5 -5
View File
@@ -2,7 +2,7 @@
// System Imports
import { useState, useEffect } from "react";
import { auth, database } from "../../../firebase-config";
import { ref, onValue, get } from "firebase/database";
import { ref, onValue } from "firebase/database";
import { useAuthState } from "react-firebase-hooks/auth"
@@ -84,7 +84,7 @@ function UserProfile() {
var i = 0;
for (var interest in interests) {
if (i < 4)
interestArray.push(<Interest interest={interests[interest]} />);
interestArray.push(<Interest interest={interests[interest]} key={interest}/>);
i++;
}
setUserInterestArray(interestArray);
@@ -93,7 +93,7 @@ function UserProfile() {
var rooms = snapshot.val().rooms;
var roomArray = [];
for (var room in rooms) {
roomArray.push(<ProfileRoom room={rooms[room]} />);
roomArray.push(<ProfileRoom room={rooms[room]} key={room}/>);
}
setUserRoomsArray(roomArray);
});
@@ -119,7 +119,7 @@ function UserProfile() {
{/* Left Side of Page */}
<div className="h-dvh md:overflow-hidden">
{/* Header */}
<Header user={user} />
<Header user={user} mainTab={"profile"} />
{/* Main Page Section */}
<div className="md:grid md:grid-cols-3 mr-2 h-[calc(100%-110px)] pl-5 pr-5 pt-2 max-md:mb-10">
<div className="cols-span-1 bg-white shadow-2xl rounded-xl pt-5 max-md:pb-5">
@@ -127,7 +127,7 @@ function UserProfile() {
<div>
<img
src={profileData.pfp}
className="relative mx-auto rounded-2xl overflow-hidden w-[90%]"
className="relative mx-auto rounded-2xl overflow-hidden max-h-[20%] max-w-[70%]"
/>
<div className="font-bold text-[30px] flex justify-center items-center">
{profileData.lastOnline == true && <CircleIcon className="text-lime-600 mr-3"/>}{profileData.firstName} {profileData.lastName}
+88 -48
View File
@@ -11,6 +11,17 @@ import PersonIcon from '@mui/icons-material/Person';
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
import CircleIcon from '@mui/icons-material/Circle';
import { TextToSpeech } from 'tts-react'
// Chat Commands Dictionary
const chatCommands = {
"/peter": "https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExcThtYjMxcWk2NG55YTE3OHdvNWJwcXVrZzV1ZmZkdWJ6cHBremFwdiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/13w5HmyiuaZ224/giphy.gif",
"/shrug": "¯\\_(ツ)_/¯",
"/tableflip": "(╯°□°)╯︵ ┻━┻",
"/unflip": "┬─┬ ( ゜-゜ノ)",
"/snoop": "https://media1.tenor.com/m/cIUjlvgnFRgAAAAd/dog-snoop.gif"
}
// Colors for Messages
const userColors = [
"#ff80ed",
@@ -43,18 +54,17 @@ let dateOptions = {
* @returns {Boolean} - Image Loaded (True) or Not (False)
*/
function imageProcessing(url) {
var x = async () => {
var x = new Promise((resolve) => {
var img = new Image();
img.src = url;
img.onload = function() {
return true;
img.onload = () => {
resolve([true, url]);
}
img.onerror = function() {
return false;
img.onerror = () => {
resolve([false, url]);
}
}
var res = x()
return res
})
return x
}
@@ -63,28 +73,42 @@ function imageProcessing(url) {
* @param {String} message - Message to Format
* @returns {String} - Formatted Message (IN HTML)
*/
export function RMF(message) {
var URLREGEX = /[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
var URLmatch = message.match(URLREGEX);
var newMessage = URLmatch ? [] : message
if (URLmatch) {
for (var i = 0; i < URLmatch.length; i++) {
if (imageProcessing("https://"+URLmatch[i])) {
newMessage.push((<span className="mr-2">
{(URLmatch.length == 1) && message.split(URLmatch[i])[0].replace("https://","").replace("http://","")}
<img src={"https://"+URLmatch[i]} className="max-w-[100%]"/>
{(i == URLmatch.length || URLmatch.length == 1) && message.split(URLmatch[i])[1]}
</span>))
} else {
newMessage.push((<span className="mr-2">
{URLmatch.length == 1 && message.split(URLmatch[i])[0]}
<Link href={"https://"+URLmatch[i]} target="_blank" className="hover:underline">{URLmatch[i]}</Link>
{(i == URLmatch.length || URLmatch.length == 1) && message.split(URLmatch[i])[1]}
</span>))
export async function RMF(message) {
var x = new Promise(async (resolve) => {
var URLREGEX = /[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
var URLmatch = message.match(URLREGEX);
var newMessage = URLmatch ? [] : message
if (URLmatch) {
for (var i = 0; i < URLmatch.length; i++) {
if (URLmatch[i].includes("chatma.ps") ) {
// Rich Message Formatting for Chat Maps
if (URLmatch[i].includes("/chat?")) {
var roomName = URLmatch[i].split("?")[1].split("/")[2].split("-")[0].replaceAll("%20"," ")
newMessage.push((<span className="italic" key={roomName}>invites you to <Link href={"https://"+URLmatch[i]} className="underline" target="_blank">{roomName}</Link></span>))
}
} else {
await imageProcessing("https://"+URLmatch[i]).then((result) => {
if (result[0]) {
newMessage.push((<span className="mr-2" key={URLmatch[i]}>
{(URLmatch.length == 1) && message.split(result[1])[0].replace("https://","").replace("http://","")}
<img src={result[1]} className="max-w-[100%]"/>
{(i == URLmatch.length || URLmatch.length == 1) && message.split(result[1])[1]}
</span>))
} else {
newMessage.push((<span className="mr-2" key={URLmatch[i]}>
{URLmatch.length == 1 && message.split(URLmatch[i])[0]}
<Link href={result[1]} target="_blank" className="hover:underline">{URLmatch[i]}</Link>
{(i == URLmatch.length || URLmatch.length == 1) && message.split(URLmatch[i])[1]}
</span>))
}
})
}
}
}
}
return newMessage
resolve(newMessage)
});
return x
}
/**
* Grabs Window Size
@@ -132,31 +156,47 @@ const generateColor = (user_str) => {
* @returns {Object} - Chat Message Component
*/
export function Chat({ chatObj, user, path }) {
const [message, setMessage] = useState([])
function deleteMessage() {
remove(ref(database, `${path}/chats/${chatObj.timestamp}-${chatObj.user}`))
}
var messageFilterBypass = [undefined, null, '', ' ', '\'', '\"']
if (!messageFilterBypass.includes(chatObj.body) && (chatObj.body.length != 1 && !chatObj.body[0].match(/\W/))) {
var message = filter.clean(chatObj.body)
message = RMF(message)
} else {
var message = chatObj.body
if (chatObj.body in chatCommands) {
chatObj.body = chatCommands[chatObj.body]
}
useEffect(() => {
// Peter Griffin Easter Egg and others
var messageFilterBypass = [undefined, null, '', ' ', '\'', '\"']
if (!messageFilterBypass.includes(chatObj.body) && (chatObj.body.length != 1 && !chatObj.body[0].match(/\W/))) {
var settingMessage = filter.clean(chatObj.body)
RMF(settingMessage).then((result) => {
setMessage(result)
})
} else {
setMessage(chatObj.body)
}
}, [])
return (
<div className="width-[100%] bg-white rounded-lg mt-1 text-left p-1 grid grid-cols-2 mr-2">
<div>
{user.uid == chatObj.uid && <DeleteOutlineIcon fontSize="" className="ml-1 mr-1 cursor-pointer" onClick={() => {deleteMessage()}}/>}
<span className="mr-[5px]" style={{ color: userColors[generateColor(chatObj.user)] }}>
<Link href={`/user?uid=${chatObj.uid}`}
className="hover:font-bold cursor-pointer">
{chatObj.user}
</Link>
</span>
{message}
</div>
<div className="text-right text-[#d1d1d1]">
{new Date(chatObj.timestamp).toLocaleString(dateOptions)}
</div>
<div>
{message && (
<div className="width-[100%] bg-white rounded-lg mt-1 text-left p-1 grid grid-cols-2 mr-2">
<div>
{user.uid == chatObj.uid && <DeleteOutlineIcon fontSize="" className="ml-1 mr-1 cursor-pointer" onClick={() => {deleteMessage()}}/>}
<span className="mr-[5px]" style={{ color: userColors[generateColor(chatObj.user)] }}>
<Link href={`/user?uid=${chatObj.uid}`}
className="hover:font-bold cursor-pointer">
{chatObj.user}
</Link>
</span>
{(typeof message == 'string' && message.substring(0,4) == "/tts")? (<TextToSpeech autoPlay={true}> {chatObj.user + " said " + filter.clean(message.substring(5,message.length))} </TextToSpeech>): message}
</div>
<div className="text-right text-[#d1d1d1]">
{new Date(chatObj.timestamp).toLocaleString(dateOptions)}
</div>
</div>
)}
</div>
);
}
@@ -71,7 +71,7 @@ export function DMRoom({ roomObj, user }) {
chatObj={messages[message]}
user={user}
path={"/dms/" + chatRoomObj.room}
key={messages[message].timestamp}
key={messages[message].timestamp + "-" + messages[message].user}
/>
);
}
+18 -16
View File
@@ -14,6 +14,7 @@ import MenuIcon from '@mui/icons-material/Menu';
import AddIcon from '@mui/icons-material/Add';
import RemoveIcon from '@mui/icons-material/Remove';
import CloseIcon from '@mui/icons-material/Close';
import { useEffect } from "react";
/**
* Closes Chat
@@ -21,8 +22,12 @@ import CloseIcon from '@mui/icons-material/Close';
* @param {JSON} user - User Object
* @returns {void}
*/
function closeChat(chatRoomObj, user) {
function closeChat(chatRoomObj, user, mainTab) {
if (mainTab == "chat") {
remove(ref(database, `/rooms/${chatRoomObj.path}/${chatRoomObj.name}-${chatRoomObj.timestamp}/users/online/${user.uid}`))
} else {
remove(ref(database, `/dms/${chatRoomObj.room}/users/online/${user.uid}`))
}
}
@@ -49,6 +54,7 @@ function addToMyRooms(chatRoomObj, user) {
);
var path =
chatRoomObj.path + "/" + chatRoomObj.name + "-" + chatRoomObj.timestamp;
user.lastOnline = serverTimestamp();
set(ref(database, `/rooms/${path}/users/all/${user.uid}`), user);
}
@@ -90,12 +96,14 @@ export function Header({mainTab,chatRoomObj,user,sidebarControl}) {
}
// Sets User Online / Offline
// Stored in header for easy code maintenance and retains user online/offline throughout app
// Makes user online
if (user.invisibleStatus == false) {
set(ref(database, `/users/${user.uid}/lastOnline`), true)
}
useEffect(() => {
// Sets User Online / Offline
// Stored in header for easy code maintenance and retains user online/offline throughout app
// Makes user online
if (user.invisibleStatus == false) {
set(ref(database, `/users/${user.uid}/lastOnline`), true)
}
}, [])
// Makes user offline (with last time online)
onDisconnect(ref(database, `/users/${user.uid}/lastOnline`)).set(serverTimestamp())
@@ -124,7 +132,6 @@ export function Header({mainTab,chatRoomObj,user,sidebarControl}) {
<a
onClick={() => {
removeFromMyRooms(chatRoomObj, user);
}}
className="p-2 cursor-pointer bg-cyan-500 text-white font-bold rounded-full mr-2 flex items-center"
>
@@ -135,7 +142,7 @@ export function Header({mainTab,chatRoomObj,user,sidebarControl}) {
<Link
href="/app"
className="p-2 cursor-pointer bg-cyan-500 text-white font-bold rounded-full mr-2 flex items-center"
onClick={() => {closeChat(chatRoomObj,user)}}
onClick={() => {closeChat(chatRoomObj,user, mainTab)}}
>
<CloseIcon/>
</Link>
@@ -148,13 +155,8 @@ export function Header({mainTab,chatRoomObj,user,sidebarControl}) {
<ProfilePanel user={user}/>
{/* Sidebar Control (for small screens) */}
<div
className="md:hidden p-2 cursor-pointer bg-cyan-500 text-white font-bold rounded-full mr-5 flex items-center"
onClick={() => {sidebarControl()}}
>
<MenuIcon/>
</div>
</div>
{mainTab !== "profile" && (<div className="md:hidden p-2 cursor-pointer bg-cyan-500 text-white font-bold rounded-full mr-5 flex items-center" onClick={() => {sidebarControl()}}><MenuIcon/></div>)}
</div>
</div>
);
}
+44 -75
View File
@@ -1,49 +1,11 @@
import { Map, Marker, ZoomControl, Overlay } from "pigeon-maps";
import { database } from "../../../../firebase-config";
import { ref, get} from "firebase/database";
import { useState } from "react";
import { useEffect, useState } from "react";
import ChatBubbleTwoToneIcon from '@mui/icons-material/ChatBubbleTwoTone';
import PersonOutlineTwoToneIcon from '@mui/icons-material/PersonOutlineTwoTone';
import { red } from '@mui/material/colors';
/**
* Nearby Markers Grabber
* @param {JSON} location - Location Object {latitude, longitude}
* @returns {Array} - Array of Markers {<Marker>}
*/
function NearbyMarkers(location) {
const [newMarkers, setNewMarkers] = useState(null);
if (location) {
const path = String(location.latitude.toFixed(2)).replace(".", "") +"/" +String(location.longitude.toFixed(2)).replace(".", "") +"/";
get(ref(database, `/rooms/${path}`)).then((snapshot) => {
if (snapshot.exists()) {
const rooms = snapshot.val();
setNewMarkers(rooms)
}
})
}
return newMarkers;
}
/**
* Friend Markers Grabber
* @param {JSON} user - User Object
* @returns {Array} - Array of Markers {<Marker>}
*/
function FriendMarkers(user) {
var friendMarkers = []
if (user && "friends" in user && "friends" in user.friends) {
for (var friend in user.friends.friends) {
get(ref(database, `/users/${friend}`)).then((snapshot) => {
var friendData = snapshot.val();
if (friendData.location) {
friendMarkers.push(friendData);
}
});
}
}
}
/**
* Geo Component for Wrapping Map
* @constructor
@@ -57,44 +19,51 @@ export function Geo({ loc, zoom, moveable, user }) {
const [hovering, setHovering] = useState(false);
const [hoverText, setHoverText] = useState("");
const [hoverAnchor, setHoverAnchor] = useState([null,null]);
const [nearbyMarkersFinal, setNearbyMarkers] = useState(null);
if (moveable) {
if (user.rooms) {
// Load My Rooms Markers
var myRoomsMarkers = Object.values(user.rooms).map((roomObj) => {
return (<Marker
key={roomObj.path + "-" + roomObj.name}
anchor={[roomObj.latitude, roomObj.longitude]}
onClick={() => {window.location.href = "/chat?room=" + roomObj.path + "/" + roomObj.name + "-" + roomObj.timestamp;}}
style={{pointerEvents:'auto'} /* So stupid */}
onMouseOver={() => {setHoverText(roomObj.name);setHovering(true);setHoverAnchor([roomObj.latitude, roomObj.longitude])}}
onMouseOut={() => {setHovering(false)}}
>
<ChatBubbleTwoToneIcon color="primary" fontSize="large"/>
</Marker>)
})
}
// Load Nearby Markers
var nearbyMarkers = NearbyMarkers(loc);
if (nearbyMarkers) {
var nearbyMarkers = Object.values(nearbyMarkers).map((roomObj) => {
return (<Marker
key={roomObj.path + "-" + roomObj.name}
anchor={[roomObj.latitude, roomObj.longitude]}
onClick={() => {window.location.href = "/chat?room=" + roomObj.path + "/" + roomObj.name + "-" + roomObj.timestamp;}}
style={{pointerEvents:'auto'} /* So stupid */}
onMouseOver={() => {setHoverText(roomObj.name);setHovering(true);setHoverAnchor([roomObj.latitude, roomObj.longitude])}}
onMouseOut={() => {setHovering(false)}}
>
<ChatBubbleTwoToneIcon color="secondary" fontSize="large"/>
</Marker>)
})
}
if (moveable && user.rooms) {
// Load My Rooms Markers
var myRoomsMarkers = Object.values(user.rooms).map((roomObj) => {
return (<Marker
key={roomObj.path + "-" + roomObj.name}
anchor={[roomObj.latitude, roomObj.longitude]}
onClick={() => {window.location.href = "/chat?room=" + roomObj.path + "/" + roomObj.name + "-" + roomObj.timestamp;}}
style={{pointerEvents:'auto'} /* So stupid */}
onMouseOver={() => {setHoverText(roomObj.name);setHovering(true);setHoverAnchor([roomObj.latitude, roomObj.longitude])}}
onMouseOut={() => {setHovering(false)}}
>
<ChatBubbleTwoToneIcon color="primary" fontSize="large"/>
</Marker>)
})
}
useEffect(() => {
// Load Nearby Markers
if (moveable && loc) {
const path = String(loc.latitude.toFixed(2)).replace(".", "") +"/" +String(loc.longitude.toFixed(2)).replace(".", "") +"/";
get(ref(database, `/rooms/${path}`)).then((snapshot) => {
console.log("ran")
if (snapshot.exists()) {
nearbyMarkers = snapshot.val();
if (nearbyMarkers) {
var nearbyMarkers = Object.values(nearbyMarkers).map((roomObj) => {
return (<Marker
key={roomObj.path + "-" + roomObj.name}
anchor={[roomObj.latitude, roomObj.longitude]}
onClick={() => {window.location.href = "/chat?room=" + roomObj.path + "/" + roomObj.name + "-" + roomObj.timestamp;}}
style={{pointerEvents:'auto'} /* So stupid */}
onMouseOver={() => {setHoverText(roomObj.name);setHovering(true);setHoverAnchor([roomObj.latitude, roomObj.longitude])}}
onMouseOut={() => {setHovering(false)}}
>
<ChatBubbleTwoToneIcon color="secondary" fontSize="large"/>
</Marker>)
})
setNearbyMarkers(nearbyMarkers);
}
}
})
}
}, [])
if (!loc) {
return <div>Getting Location...</div>;
@@ -109,7 +78,7 @@ export function Geo({ loc, zoom, moveable, user }) {
attribution={false}
>
{zoom && <ZoomControl />}
{moveable && nearbyMarkers}
{moveable && nearbyMarkersFinal}
{moveable && myRoomsMarkers}
{ /* Overlay */}
@@ -56,7 +56,7 @@ export function ChatRoom({ roomObj, user }) {
chatsArr.push(
<SystemMessage
chatObj={messages[message]}
key={messages[message].timestamp}
key={messages[message].timestamp + messages[message].user}
/>
);
} else {
@@ -65,7 +65,7 @@ export function ChatRoom({ roomObj, user }) {
chatObj={messages[message]}
user={user}
path={"/rooms/" + chatRoomObj.path + "/" + chatRoomObj.name + "-" + chatRoomObj.timestamp}
key={messages[message].timestamp}
key={messages[message].timestamp + "-" + messages[message].user}
/>
);
}
@@ -17,7 +17,7 @@ export function Sidebar({chatRoomObj}) {
var activeUsers = [];
var activeUsersJSON = chatRoomObj.users.online;
for (var user in activeUsersJSON)
activeUsers.push(<Member memberObj={activeUsersJSON[user]} />);
activeUsers.push(<Member memberObj={activeUsersJSON[user]} key={user}/>);
var chatroomOnline = activeUsers
}
@@ -29,7 +29,7 @@ export function Sidebar({chatRoomObj}) {
var allUsers = [];
var allUsersJSON = chatRoomObj.users.all;
for (var user in allUsersJSON)
allUsers.push(<Member memberObj={allUsersJSON[user]} />);
allUsers.push(<Member memberObj={allUsersJSON[user]} key={user}/>);
var chatroomUsers = allUsers
}
return (
+10 -12
View File
@@ -1,24 +1,22 @@
import { Member } from "../datatypes"
import { database } from "../../../../firebase-config"
import {ref, get, onValue} from "firebase/database"
import {ref, get} from "firebase/database"
import { useState, useEffect } from "react"
export function Sidebar({user, chatRoomObj}) {
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]} key={activeUser} />);
}
})
useEffect(() => {
if (chatRoomObj.users && chatRoomObj.users.online) {
var activeUsers = []
for (var activeUser in chatRoomObj.users.online)
activeUsers.push(<Member memberObj={chatRoomObj.users.online[activeUser]} key={activeUser} />);
}
setChatroomOnline(activeUsers)
}, [chatRoomObj])
useEffect(() => {
if (user) {
// Profile Information
@@ -49,7 +47,7 @@ export function Sidebar({user, chatRoomObj}) {
</div>
<div className="bg-white rounded-lg m-2 shadow-2xl">
<div>In The Chat</div>
{activeUsers}
{chatroomOnline}
</div>
</div>
</div>
@@ -89,26 +89,28 @@ function classNames(...classes) {
* @returns {Object} - App Page Sidebar Component
*/
export function Sidebar({user,location,loadingLoc}) {
const [friends, setFriends] = useState([])
const [friends, setFriends] = useState(null)
const [friendRequests, setFriendRequests] = useState(null)
const [dms, setDMs] = useState((<div>No DMs</div>))
const [myRoomArr, setMyRoomArr] = useState([])
const [myRoomArr, setMyRoomArr] = useState(null)
useEffect(() => {
var myRoomArr = [];
// Add myRooms to Sidebar
for (var room in user.rooms) {
get(ref(database, `/rooms/${user.rooms[room].path}/${user.rooms[room].name}-${user.rooms[room].timestamp}`)).then((snapshot) => {
var newRoom = (
<ChatRoomSidebar
roomObj={snapshot.val()}
key={snapshot.val().timestamp}
/>
);
myRoomArr.push(newRoom);
})
if (user && myRoomArr == null) {
var myRoomArr = [];
// Add myRooms to Sidebar
for (var room in user.rooms) {
get(ref(database, `/rooms/${user.rooms[room].path}/${user.rooms[room].name}-${user.rooms[room].timestamp}`)).then((snapshot) => {
var newRoom = (
<ChatRoomSidebar
roomObj={snapshot.val()}
key={snapshot.val().timestamp}
/>
);
myRoomArr.push(newRoom);
})
}
setMyRoomArr(myRoomArr)
}
setMyRoomArr(myRoomArr)
}, [])
useEffect(() => {
@@ -154,7 +156,7 @@ export function Sidebar({user,location,loadingLoc}) {
}
})
}, [user])
}, [user.friends])
return (
<div className="h-dvh bg-[aliceblue] pt-2 pb-2 pl-2 pr-1">
@@ -166,42 +168,42 @@ export function Sidebar({user,location,loadingLoc}) {
'w-[30%]',
selected
? 'bg-cyan-500 text-white font-bold shadow hover:bg-white/[0.6] hover:text-black'
: 'hover:bg-cyan-500/[0.6] hover:text-white hover:font-bold'
: 'hover:bg-cyan-500/[0.6] hover:text-white hover:font-bold bg-[#D3D3D3] drop-shadow-none'
)}>Nearby</Tab>
<Tab className={({ selected }) =>
classNames(
'w-[30%]',
selected
? 'bg-cyan-500 text-white font-bold shadow hover:bg-white/[0.6] hover:text-black'
: 'hover:bg-cyan-500/[0.6] hover:text-white hover:font-bold'
: 'hover:bg-cyan-500/[0.6] hover:text-white hover:font-bold bg-[#D3D3D3] drop-shadow-none'
)}>My Rooms</Tab>
<Tab className={({ selected }) =>
classNames(
'w-[30%]',
selected
? 'bg-cyan-500 text-white font-bold shadow hover:bg-white/[0.6] hover:text-black'
: 'hover:bg-cyan-500/[0.6] hover:text-white hover:font-bold'
: 'hover:bg-cyan-500/[0.6] hover:text-white hover:font-bold bg-[#D3D3D3] drop-shadow-none'
)}>Create</Tab>
<Tab className={({ selected }) =>
classNames(
'w-[30%]',
selected
? 'bg-cyan-500 text-white font-bold shadow hover:bg-white/[0.6] hover:text-black'
: 'hover:bg-cyan-500/[0.6] hover:text-white hover:font-bold'
: 'hover:bg-cyan-500/[0.6] hover:text-white hover:font-bold bg-[#D3D3D3] drop-shadow-none'
)}>DMs</Tab>
<Tab className={({ selected }) =>
classNames(
'w-[30%]',
selected
? 'bg-cyan-500 text-white font-bold shadow hover:bg-white/[0.6] hover:text-black'
: 'hover:bg-cyan-500/[0.6] hover:text-white hover:font-bold'
: 'hover:bg-cyan-500/[0.6] hover:text-white hover:font-bold bg-[#D3D3D3] drop-shadow-none'
)}>Friends</Tab>
<Tab className={({ selected }) =>
classNames(
'w-[30%]',
selected
? 'bg-cyan-500 text-white font-bold shadow hover:bg-white/[0.6] hover:text-black'
: 'hover:bg-cyan-500/[0.6] hover:text-white hover:font-bold'
: 'hover:bg-cyan-500/[0.6] hover:text-white hover:font-bold bg-[#D3D3D3] drop-shadow-none'
)}>Requests</Tab>
</Tab.List>
@@ -10,7 +10,7 @@ export function NearbySidebar({location}) {
const [nearbyArr, setNearbyArr] = useState([])
const [displayedRooms, setDisplayedRooms] = useState([])
const [nearbyArrReady, setNearbyArrReady] = useState(false)
const {register, watch, setFocus} = useForm({defaultValues: {search: null}})
const {register, watch, setFocus} = useForm({defaultValues: {search: ""}})
// Search Bar Value
const search = watch("search")
@@ -19,7 +19,7 @@ export function NearbySidebar({location}) {
function SearchBar() {
return (
<div className="w-[97%]">
<input type="text" placeholder="Search" {...register("search")} className="w-full p-2 border-2 border-gray-300 rounded-lg col-span-3" value={null} />
<input type="text" placeholder="Search" {...register("search")} className="w-full p-2 border-2 border-gray-300 rounded-lg col-span-3" value={" "} />
</div>
)
}