diff --git a/frontend-next/package-lock.json b/frontend-next/package-lock.json
index 7d4b26b..3a0c916 100644
--- a/frontend-next/package-lock.json
+++ b/frontend-next/package-lock.json
@@ -13,6 +13,7 @@
"next": "^14.1.0",
"pigeon-maps": "^0.21.3",
"react": "^18.2.0",
+ "react-beforeunload": "^2.6.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.50.1"
},
@@ -5739,6 +5740,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-beforeunload": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/react-beforeunload/-/react-beforeunload-2.6.0.tgz",
+ "integrity": "sha512-aKrGaRNc7fZQlDnmSYrXu4cbz9QEPhScA4A2mLxhjcULDy4VILLyLhSEjg2goIw3o5LQ1zss44kmQh5LXWYGCw==",
+ "peerDependencies": {
+ "react": "^16.8.0 || 17 || 18"
+ }
+ },
"node_modules/react-dom": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
diff --git a/frontend-next/package.json b/frontend-next/package.json
index 1912fa3..544379a 100644
--- a/frontend-next/package.json
+++ b/frontend-next/package.json
@@ -14,6 +14,7 @@
"next": "^14.1.0",
"pigeon-maps": "^0.21.3",
"react": "^18.2.0",
+ "react-beforeunload": "^2.6.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.50.1"
},
diff --git a/frontend-next/src/app/app/page.js b/frontend-next/src/app/app/page.js
index ad74268..def0b53 100644
--- a/frontend-next/src/app/app/page.js
+++ b/frontend-next/src/app/app/page.js
@@ -1,12 +1,16 @@
"use client"
-import { useState, useEffect, createContext, useContext } from 'react'
+import { useState, useEffect } from 'react'
import {Map, Marker, ZoomControl} from "pigeon-maps"
import { Form, useForm } from "react-hook-form";
import { app } from "../api/firebase-config";
-import { getDatabase, ref, onValue, get, set} from "firebase/database";
+import { getDatabase, ref, onValue, get, set, remove} from "firebase/database";
+import { useBeforeunload } from 'react-beforeunload';
var database = getDatabase(app)
-// Data types
+
+// Data Types
+
+// Chat Message
function Chat({chatObj}) {
let dateOptions = {
weekday: 'long',
@@ -28,9 +32,45 @@ function Chat({chatObj}) {
)
}
+// System Chat Message
+function SystemMessage({chatObj}) {
+ let dateOptions = {
+ weekday: 'long',
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric',
+ hour: '2-digit',
+ minute: '2-digit'
+ };
+ return (
+
+
+ {chatObj.user} has {chatObj.body} the room.
+
+
+ {new Date(chatObj.timestamp).toLocaleString(dateOptions)}
+
+
+ )
+}
+
+// Member for Active/Room members in sidebar
+function Member({memberObj}) {
+ return (
+
+ {memberObj.username}
+
+ )
+}
+
+// Chat Room for myRooms and Nearby in sidebar
function ChatRoomSidebar({roomObj, click}) {
+ // TODO: Gross fix but it works
+function clicker() {
+ click(roomObj.name+"-"+roomObj.timestamp, roomObj)
+}
return (
-
+
{roomObj.name}
{roomObj.description}
@@ -39,9 +79,27 @@ return (
)
}
+// Map module for main page and chat room sidebar
+// TODO: MAKE NOT MOVABLE
+function Geo({loc, zoom, movable, locMarker, markers}) {
+ if (loc) {
+ return (
+
+ {markers && markers}
+ {locMarker && }
+ {zoom && }
+
+ )
+ } else {
+ return (
+
+ )
+ }
+
+}
+// Module for Welcome Message on main tab landing page
function WelcomeMessage() {
- //TODO: REALLY GROSS WAY TO GET COOKIES, NEED NEW WAY TO STORE USER DATA WITHOUT API CALLS. THIS PAGE HAS TO BE CLIENT SIDE DUE TO MAPS / GEOLOCATION
const [data, setData] = useState(null)
const [isLoading, setLoading] = useState(true)
useEffect(() => {
@@ -68,55 +126,36 @@ function WelcomeMessage() {
}
-function Geo({loc}) {
- if (loc) {
- return (
-
-
-
-
- )
- } else {
- return (
-
- )
- }
-
-}
-
-
-
// Main Tabs
-function MainTabHome({loc}) {
+// Primary App Landing Page
+function MainTabHome({loc, markers}) {
return (
<>
-
+
>
)
}
-function MainTabChatRoom({room}) {
+// Chatroom Module for Primary Tab
+function MainTabChatRoom({roomObj}) {
var { register, control, reset, handleSubmit} = useForm()
const [chats, setData] = useState(null)
const [isLoading, setLoading] = useState(true)
- var user
- fetch('/api/user')
- .then((res) => res.json())
- .then((data) => {
- user = data
- })
-
- var unsubscribeUpdater
+ // Message updater
useEffect(() => {
- unsubscribeUpdater = onValue(ref(database, `/rooms/${room}/chats`), (snapshot) => {
+ onValue(ref(database, `/rooms/${roomObj.path+"/"+roomObj.name+"-"+roomObj.timestamp}/chats`), (snapshot) => {
var chatsArr = []
var messages = snapshot.val()
for (var message in messages) {
- chatsArr.push()
+ if (messages[message].isSystem) {
+ chatsArr.push()
+ } else {
+ chatsArr.push()
+ }
}
setData(chatsArr.reverse())
setLoading(false)
@@ -125,15 +164,18 @@ function MainTabChatRoom({room}) {
function sendMessage(data) {
reset()
- var payload = {
- body: data.message,
- user: user.username,
- timestamp: new Date().getTime()
- }
- set(ref(database,`/rooms/${room}/chats/${user.username}-${new Date().getTime()}`), payload)
+ fetch('/api/user').then((res) => res.json())
+ .then((user) => {
+ var payload = {
+ body: data.message,
+ user: user.username,
+ isSystem: false,
+ timestamp: new Date().getTime()
+ }
+ set(ref(database,`/rooms/${roomObj.path+"/"+roomObj.name+"-"+roomObj.timestamp}/chats/${new Date().getTime()}-${user.username}`), payload)
+ })
}
-
if (isLoading) return Loading
if (!chats) return No Chats
return (
@@ -151,65 +193,52 @@ function MainTabChatRoom({room}) {
)
}
-function CreateRoom({loc}) {
- var { register, control, reset, handleSubmit} = useForm()
-
- function createRoom(data) {
- reset()
- var path = String(loc.latitude.toFixed(2)).replace(".","")+"/"+String(loc.longitude.toFixed(2)).replace(".","")
- var timestamp = new Date().getTime()
- var payload = {
- name: data.name,
- description: data.description,
- timestamp: timestamp,
- latitude: loc.latitude,
- longitude: loc.longitude,
- path: path
- }
- set(ref(database,`/rooms/${path}/${data.name}-${timestamp}`), payload)
- }
-
- return (
-
- )
-}
-
+// Contains most everything for the app homepage
+//
function Home() {
- var [tab, setTab] = useState("nearby")
- var [mainTab, setMainTab] = useState("home")
- var [chatRoom, setChatRoom] = useState("Dev")
+ // It's time to document and change these awful variable names
+ // State variables for app page
+ const [mainTab, setMainTab] = useState("home") // Primary tab
+ const [tab, setTab] = useState("nearby") // Sidebar Tab
+ const [chatRoomObj, setChatRoomObj] = useState(null) // Current chatroom object
+ const [myRoomsObj, setMyRoomsObj] = useState(null) // My Rooms Object
+ const [myRooms, setRoomData] = useState(null) // Current user saved rooms list
+ const [isRoomLoading, setRoomLoading] = useState(true) // myRooms loading variable, true = myRooms loading, false = finished loading
+ const [isMyRoom, setIsMyRoom] = useState(false) // Is current room in myRooms? true, false
+ const [location, setLocation] = useState(null) // location variable [lat,long]
+ const [loadingLoc, setLoadingLoc] = useState(true) // location variable loading, true = loading, false = finished loading
+ const [nearby, setNearby] = useState(null); // nearby rooms array
+ const [loadingNearby, setLoadingNearby] = useState(true); // loading nearby rooms array, true = loading, false = finished loading
+ const [chatroomOnline, setChatRoomOnline] = useState(null) // holds online users
+ const [chatroomUsers, setChatroomUsers] = useState(null) // holds all chatroom users
+ const [chatroomUsersLoading ,setChatroomUsersLoading] = useState(true)
+ const [users, setUsers] = useState(null) // all users from firebase
+ const [alreadyLeft, setAlreadyLeft] = useState(false) // if already left from room
+ const [markers, setMarkers] = useState([])
- const [myRooms, setRoomData] = useState(null)
- const [isRoomLoading, setRoomLoading] = useState(true)
+ // Grabs user data, saves to user, then lists the users saved rooms
useEffect(() => {
- fetch('/api/user').then((res) => res.json())
- .then((user) => {
- get(ref(database, '/users/'+user.uid+'/rooms')).then((snapshot) => {
- var rooms = snapshot.val()
- var roomArr = []
- for (var room in rooms) {
- roomArr.push( {setChatRoom(rooms[room].path+"/"+rooms[room].name+"-"+rooms[room].timestamp);setMainTab("chat")}}/>)
- }
- setRoomData(roomArr)
- setRoomLoading(false)
- })
- })
- }, [])
+ fetch('/api/user').then((res) => res.json())
+ .then((user) => {
+ onValue(ref(database, '/users/'+user.uid+'/rooms'),(snapshot) => {
+ setRoomLoading(true)
+ var rooms = snapshot.val()
+ setMyRoomsObj(rooms)
+ var roomArr = []
+ var markerArr = markers
+ for (var room in rooms) {
+ var newRoom =
+ markerArr.push( )
+ roomArr.push(newRoom)
+ }
+ setMarkers(markerArr)
+ setRoomData(roomArr)
+ setRoomLoading(false)
+ })
+ })
+}, [])
-
- const [location, setLocation] = useState(null);
- const [loadingLoc, setLoadingLoc] = useState(true)
- const [nearby, setNearby] = useState(null);
- const [loadingNearby, setLoadingNearby] = useState(true);
+ // Grabs the user location
useEffect(() => {
if('geolocation' in navigator) {
// Retrieve latitude & longitude coordinates from `navigator.geolocation` Web API
@@ -218,12 +247,16 @@ function Home() {
setLoadingLoc(false)
var nearbyArr = []
var path = String(coords.latitude.toFixed(2)).replace(".","")+"/"+String(coords.longitude.toFixed(2)).replace(".","")
+ var markersArr = markers
get(ref(database, `/rooms/${path}`)).then((snapshot) => {
if (snapshot.exists()) {
var data = snapshot.val()
for (var room in data) {
- nearbyArr.push( {setChatRoom(data[room].path+"/"+data[room].name+"-"+data[room].timestamp);setMainTab("chat")}}/>)
+ nearbyArr.push()
+ // TODO: RANDOM LAST DIGIT TO MOVE AROUND THE MAP
+ markersArr.push( )
}
+ setMarkers(markersArr)
setLoadingNearby(false)
setNearby(nearbyArr)
} else {
@@ -234,25 +267,204 @@ function Home() {
}
}, []);
+ // Grab list of all users
+ useEffect(() => {
+ get(ref(database, `/users`)).then((snapshot) => {
+ setUsers(snapshot.val())
+ })
+
+ }, []);
+
+ // Dont Double Send Leaving Message
+ useEffect(() => {
+ if (myRoomsObj && chatRoomObj) {
+ var roomName = chatRoomObj.name+"-"+chatRoomObj.timestamp
+ if (myRooms != null && roomName in myRoomsObj) {
+ // its in there
+ setIsMyRoom(true)
+ } else {
+ // its not in there
+ setIsMyRoom(false)
+ }
+ }
+ }, [chatRoomObj])
+
+ // CreateRoom Module for Sidebar Create Tab
+ function CreateRoom({loc}) {
+ var { register, control, reset, handleSubmit} = useForm()
+
+ function createRoom(data) {
+ reset()
+ var path = String(loc.latitude.toFixed(2)).replace(".","")+"/"+String(loc.longitude.toFixed(2)).replace(".","")
+ var timestamp = new Date().getTime()
+ var payload = {
+ name: data.name,
+ description: data.description,
+ timestamp: timestamp,
+ latitude: loc.latitude,
+ longitude: loc.longitude,
+ path: path
+ }
+ set(ref(database,`/rooms/${path}/${data.name}-${timestamp}`), payload)
+ }
+
+ return (
+
+ )
+ }
+
+ // Selects chat room
+ function selectChatRoom(roomName, roomObj) {
+ fetch('/api/user').then((res) => res.json())
+ .then((user) => {
+ // Path of chatroom
+ var path = roomObj.path+"/"+roomObj.name+"-"+roomObj.timestamp
+
+ setChatRoomObj(roomObj)
+
+ // Send entered message
+ var payload = {
+ body: "entered",
+ user: user.username,
+ isSystem: true,
+ timestamp: new Date().getTime()
+ }
+ set(ref(database,`/rooms/${path}/chats/${new Date().getTime()}-${user.username}`), payload)
+
+ // Code for Room Data
+ set(ref(database, `/rooms/${path}/users/online/${user.uid}`), user)
+ onValue(ref(database, `/rooms/${path}`), (snapshot) => {
+
+ setChatRoomOnline(null)
+ setChatroomUsers(null)
+
+ // Active users list
+ if (snapshot.val().hasOwnProperty("users") && snapshot.val().users.hasOwnProperty("online")) {
+ var activeUsers = []
+ var activeUsersJSON = snapshot.val().users.online
+ for (var user in activeUsersJSON)
+ activeUsers.push()
+ setChatRoomOnline(activeUsers)
+ }
+
+ // Users who added to "my rooms"
+ console.log(snapshot.val().hasOwnProperty("users") && snapshot.val().users.hasOwnProperty("all"))
+ if (snapshot.val().hasOwnProperty("users") && snapshot.val().users.hasOwnProperty("all")) {
+ setChatroomUsersLoading(true)
+ var allUsers = []
+ var allUsersJSON = snapshot.val().users.all
+ for (var user in allUsersJSON)
+ allUsers.push()
+ setChatroomUsers(allUsers)
+ setChatroomUsersLoading(false)
+
+ }
+
+ })
+ setMainTab("chat")
+ setAlreadyLeft(false)
+ })
+ }
+
+ // Closes chat room
+ function closeChatRoom(roomObj) {
+ fetch('/api/user').then((res) => res.json())
+ .then((user) => {
+ var path = roomObj.path+"/"+roomObj.name+"-"+roomObj.timestamp
+ var payload = {
+ body: "left",
+ user: user.username,
+ isSystem: true,
+ timestamp: new Date().getTime()
+ }
+ set(ref(database,`/rooms/${path}/chats/${new Date().getTime()}-${user.username}`), payload)
+ remove(ref(database, `/rooms/${path}/users/online/${user.uid}`))
+ setChatRoomObj(null)
+ setAlreadyLeft(true)
+ setMainTab("home")
+ })
+ }
+
+ // Adds room to myRooms
+ function addToMyRooms() {
+ fetch('/api/user').then((res) => res.json())
+ .then((user) => {
+ set(ref(database,`/users/${user.uid}/rooms/${chatRoomObj.name}-${chatRoomObj.timestamp}`), {
+ name: chatRoomObj.name,
+ path: chatRoomObj.path,
+ timestamp: chatRoomObj.timestamp,
+ description: chatRoomObj.description,
+ longitude: chatRoomObj.longitude,
+ latitude: chatRoomObj.latitude,
+ })
+ var path = chatRoomObj.path+"/"+chatRoomObj.name+"-"+chatRoomObj.timestamp
+ set(ref(database, `/rooms/${path}/users/all/${user.uid}`), user)
+ })
+ setIsMyRoom(true)
+ }
+
+ // Deletes saved room from myRooms
+ function removeFromMyRooms() {
+ fetch('/api/user').then((res) => res.json())
+ .then((user) => {
+ var path = chatRoomObj.path+"/"+chatRoomObj.name+"-"+chatRoomObj.timestamp
+ remove(ref(database,`/users/${user.uid}/rooms/${chatRoomObj.name}-${chatRoomObj.timestamp}`))
+ remove(ref(database, `/rooms/${path}/users/all/${user.uid}`))
+ })
+ setIsMyRoom(false)
+ }
+
+ // Fires to tell other uses that you are leaving the room
+ useBeforeunload(() => {
+ fetch('/api/user').then((res) => res.json())
+ .then((user) => {
+ if (chatRoomObj && mainTab == "chat") {
+ var payload = {
+ body: "left",
+ user: user.username,
+ isSystem: true,
+ timestamp: new Date().getTime()
+ }
+ set(ref(database,`/rooms/${chatRoomObj.path+"/"+chatRoomObj.name+"-"+chatRoomObj.timestamp}/chats/${new Date().getTime()}-${user.username}`), payload)
+ remove(ref(database, `/rooms/${chatRoomObj.path+"/"+chatRoomObj.name+"-"+chatRoomObj.timestamp}/users/online/${user.uid}`))
+ }
+ })
+ });
return (
+ {/* Left Side of Page */}
+ {/* Header */}
+ {/* Main Page Section */}
- {(mainTab == "home" && !loadingLoc) && }
- {(mainTab == "home" && loadingLoc) && }
- {mainTab == "chat" && }
+ {(mainTab == "home" && !loadingLoc) && }
+ {(mainTab == "home" && loadingLoc) && }
+ {mainTab == "chat" && }
+ {/* Sidebar (Right Side of Page) */}
+ {mainTab == "home" &&
@@ -262,7 +474,7 @@ function Home() {
{setTab("create")}}>Create
- {tab == "nearby" &&
+ {(tab == "nearby") &&
{(!nearby && !loadingNearby) &&
No Nearby Rooms Create One?
}
{loadingNearby &&
Loading...
}
@@ -279,7 +491,41 @@ function Home() {
{(tab == "create" && !loadingLoc) &&
}
{(tab == "create" && loadingLoc) && Loading...
}
+
}
+ {(mainTab == "chat") &&
+
+
+
+
+
+
+
+ {chatRoomObj.name}
+ {chatRoomObj.description}
+
+
+
+
+ Online Members
+
+ {chatroomOnline}
+
+
+
+ All Members
+
+ {!chatroomUsersLoading && chatroomUsers}
+
+
+ }
+ {(mainTab == "profile") &&
+
+ }
)
}
diff --git a/frontend-next/src/app/login/page.js b/frontend-next/src/app/login/page.js
index 52637ce..96f2a1a 100644
--- a/frontend-next/src/app/login/page.js
+++ b/frontend-next/src/app/login/page.js
@@ -35,7 +35,7 @@ function Login() {
{(isSubmitting || isSubmitted) &&
-
+
}