diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/README.md b/README.md index c7115de..aa9e57b 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ ![](/frontend-next/public/logos/logo_transparent.png) Main repo for ChatMaps, our COS420 Project. -ChatMaps is a web-based social networking service that allows users to connect to others in their local geographic area. It will implement an interactable mapping utility to show general user locations relative to other users, as well as a chat room feature that allows users to start public conversations based on a specified topic. ChatMaps is primarily intended for use in densely populated areas, such as college campuses or metropolitan areas, so people of similar interests can start conversations. The goal of this project is to create a web app that plots locations, gives a radius of the local area, and connects users into different topic-based chat rooms. +ChatMaps is a web-based social networking service that allows users to connect to others in their local geographic area. It implements an interactable mapping utility to show general user locations relative to other users, as well as a chat room feature that allows users to start public conversations based on a specified topic. ChatMaps is primarily intended for use in densely populated areas, such as college campuses or metropolitan areas, so people of similar interests can start conversations. The goal of this project is to create a web app that plots locations, gives a radius of the local area, and connects users into different topic-based chat rooms. -This service will implement user login and profiles, allowing users to add each other as friends and start private conversations. There will be several default chat rooms of varying topics, but users will also have the ability to create their own topics that will be viewable by other users. For example, a user at the University of Maine could create a joinable chat room titled “COS420”, which would be visible to others near this campus. +This service implements user login and profiles, allowing users to add each other as friends and start private conversations. There are several default chat rooms of varying topics, but users also have the ability to create their own topics that will be viewable by other users. For example, a user at the University of Maine could create a joinable chat room titled “COS420”, which would be visible to others near this campus. This app shares some similarities to other social networks that implement location-based content. ChatMaps’ novel approach is to utilize user location to facilitate real-time communication with others within a given radius. @@ -15,6 +15,8 @@ A local version can be run with: cd frontend-next/ +npm install + npm run build npm run dev diff --git a/frontend-next/src/app/app/layout.js b/frontend-next/src/app/app/layout.js index 18a5f84..632275f 100644 --- a/frontend-next/src/app/app/layout.js +++ b/frontend-next/src/app/app/layout.js @@ -11,9 +11,7 @@ export const metadata = { export default function RootLayout({ children }) { return ( - - {children} - + {children} ); } diff --git a/frontend-next/src/app/app/page.js b/frontend-next/src/app/app/page.js index b0e0a5b..30ccac9 100644 --- a/frontend-next/src/app/app/page.js +++ b/frontend-next/src/app/app/page.js @@ -4,9 +4,8 @@ import { useState, useEffect } from "react"; import { auth, database } from "../../../firebase-config"; import { ref, onValue, set, remove, get } from "firebase/database"; import { useBeforeunload } from "react-beforeunload"; -import {Marker} from "pigeon-maps"; -import {onAuthStateChanged} from "firebase/auth" - +import { Marker } from "pigeon-maps"; +import { onAuthStateChanged } from "firebase/auth"; // Refactored Component Imports // Data Structure Imports @@ -20,7 +19,7 @@ import { MainTabChatRoom } from "../../components/app/main_tab/chat"; import { MainTabHome } from "../../components/app/main_tab/home"; // Sidebar Imports -import {Home_Sidebar} from "../../components/app/sidebar/home"; +import { Home_Sidebar } from "../../components/app/sidebar/home"; import { Chat_Sidebar } from "../../components/app/sidebar/chat"; import { Profile_Sidebar } from "../../components/app/sidebar/profile"; @@ -32,100 +31,111 @@ function Home() { 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 [roomData, setRoomData] = useState(null); // Current user saved rooms list + const [isRoomLoading, setIsRoomLoading] = 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 [chatroomOnline, setChatroomOnline] = useState(null); // holds online users const [chatroomUsers, setChatroomUsers] = useState(null); // holds all chatroom users const [chatroomUsersLoading, setChatroomUsersLoading] = useState(true); const [markers, setMarkers] = useState([]); - const [isAuthenticated, setAuth] = useState(false) - const [user, setUser] = useState(null) - const [usingSearchParams, setUsingSearchParams] = useState(true) + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [user, setUser] = useState(null); + const [usingSearchParams, setUsingSearchParams] = useState(true); useEffect(() => { const searchParams = new URLSearchParams(document.location.search); - var roomSwitch = null + var roomSwitch = null; if (searchParams.has("room") && usingSearchParams && user) { - roomSwitch = searchParams.get("room") - setUsingSearchParams(false) - get(ref(database, `rooms/${searchParams.get("room")}`)).then((snapshot) => { - selectChatRoom(snapshot.val()) - }); + roomSwitch = searchParams.get("room"); + setUsingSearchParams(false); + get(ref(database, `rooms/${searchParams.get("room")}`)).then( + (snapshot) => { + selectChatRoom(snapshot.val()); + } + ); } - }, [user]) + }, [user]); // Authentication useEffect(() => { onAuthStateChanged(auth, (user) => { if (user) { - get(ref(database, `users/${user.uid}`)) - .then((userData) => { - userData = userData.val() + get(ref(database, `users/${user.uid}`)).then((userData) => { + userData = userData.val(); if (userData) { - setUser(userData) - setAuth(true) + setUser(userData); + setIsAuthenticated(true); } else { - window.location.href = "/onboarding" + window.location.href = "/onboarding"; } - - }) + }); } else { - setAuth(false) - window.location.href = "/login" + setIsAuthenticated(false); + window.location.href = "/login"; } - }) - }, []) + }); + }, []); // Grabs user data, saves to user, then lists the users saved rooms useEffect(() => { - if (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); - }); + if (user) { + onValue(ref(database, "/users/" + user.uid + "/rooms"), (snapshot) => { + setIsRoomLoading(true); + var rooms = snapshot.val(); + setMyRoomsObj(rooms); + var roomArr = []; + var markerArr = markers; + for (var room in rooms) { + var newRoom = ( + + ); + markerArr.push( + + (window.location.href = + "/app?room=" + + rooms[room].path + + "/" + + rooms[room].name + + "-" + + rooms[room].timestamp) + } + /> + ); + roomArr.push(newRoom); } - },[user]); + setMarkers(markerArr); + setRoomData(roomArr); + setIsRoomLoading(false); + }); + } + }, [user]); // Grabs the user location useEffect(() => { if ("geolocation" in navigator && user) { // Retrieve latitude & longitude coordinates from `navigator.geolocation` Web API navigator.geolocation.getCurrentPosition(({ coords }) => { - - setLocation(coords) - setLoadingLoc(false) - var path = String(coords.latitude.toFixed(2)).replace(".","")+"/"+String(coords.longitude.toFixed(2)).replace(".","") - var markersArr = markers + setLocation(coords); + setLoadingLoc(false); + var path = + String(coords.latitude.toFixed(2)).replace(".", "") + + "/" + + String(coords.longitude.toFixed(2)).replace(".", ""); + var markersArr = markers; onValue(ref(database, `/rooms/${path}`), (snapshot) => { - var nearbyArr = [] + var nearbyArr = []; if (snapshot.exists()) { var data = snapshot.val(); for (var room in data) { @@ -138,6 +148,15 @@ function Home() { width={30} anchor={[data[room].latitude, data[room].longitude]} color="blue" + onClick={() => + (window.location.href = + "/app?room=" + + data[room].path + + "/" + + data[room].name + + "-" + + data[room].timestamp) + } /> ); } @@ -150,13 +169,13 @@ function Home() { }); }); } - },[user]); + }, [user]); // Dont Double Send Leaving Message useEffect(() => { if (myRoomsObj && chatRoomObj) { var roomName = chatRoomObj.name + "-" + chatRoomObj.timestamp; - if (myRooms != null && roomName in myRoomsObj) { + if (roomData != null && roomName in myRoomsObj) { // its in there setIsMyRoom(true); } else { @@ -168,98 +187,98 @@ function Home() { // Selects chat room function selectChatRoom(roomObj) { - // Path of chatroom - var path = roomObj.path + "/" + roomObj.name + "-" + roomObj.timestamp; + // Path of chatroom + var path = roomObj.path + "/" + roomObj.name + "-" + roomObj.timestamp; - setChatRoomObj(roomObj); + setChatRoomObj(roomObj); - // Send entered message - var payload = { - body: "entered", - user: user.username, - isSystem: true, - timestamp: new Date().getTime(), - uid: user.uid - }; - set( - ref( - database, - `/rooms/${path}/chats/${new Date().getTime()}-${user.username}` - ), - payload - ); + // Send entered message + var payload = { + body: "entered", + user: user.username, + isSystem: true, + timestamp: new Date().getTime(), + uid: user.uid, + }; + 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); + // 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); - } + // 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" - 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"); + // Users who added to "my rooms" + 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"); } // Fires to tell other uses that you are leaving the room useBeforeunload(() => { - if (chatRoomObj && mainTab == "chat") { - var payload = { - body: "left", - user: user.username, - isSystem: true, - timestamp: new Date().getTime(), - uid: user.uid - }; - 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/${userID}` - ) - ); - } + if (chatRoomObj && mainTab == "chat") { + var payload = { + body: "left", + user: user.username, + isSystem: true, + timestamp: new Date().getTime(), + uid: user.uid, + }; + 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/${userID}` + ) + ); + } }); return ( @@ -269,32 +288,54 @@ function Home() { {/* Left Side of Page */}
{/* Header */} -
+
{/* Main Page Section */}
{mainTab == "home" && !loadingLoc && ( - + )} {mainTab == "home" && loadingLoc && ( - + + )} + {mainTab == "chat" && ( + )} - {mainTab == "chat" && }
{/* Sidebar (Right Side of Page) */} {mainTab == "home" && ( - + )} {mainTab == "chat" && ( - - )} - {mainTab == "profile" && ( - + )} + {mainTab == "profile" && } )} - + ); } -export default Home; \ No newline at end of file +export default Home; diff --git a/frontend-next/src/app/globals.css b/frontend-next/src/app/globals.css index 308cb63..b9ec1dd 100644 --- a/frontend-next/src/app/globals.css +++ b/frontend-next/src/app/globals.css @@ -5,7 +5,7 @@ body { background-color: aliceblue; text-align: center; - text-wrap:pretty; + text-wrap: pretty; } button { diff --git a/frontend-next/src/app/layout.js b/frontend-next/src/app/layout.js index 927f794..16679e4 100644 --- a/frontend-next/src/app/layout.js +++ b/frontend-next/src/app/layout.js @@ -5,15 +5,13 @@ const inter = Inter({ subsets: ["latin"] }); export const metadata = { title: "ChatMaps", - description: "ChatMaps: Social Media for College Students" + description: "ChatMaps: Social Media for College Students", }; export default function RootLayout({ children }) { return ( - - {children} - + {children} ); } diff --git a/frontend-next/src/app/login/layout.js b/frontend-next/src/app/login/layout.js index fd19b66..5a6bf89 100644 --- a/frontend-next/src/app/login/layout.js +++ b/frontend-next/src/app/login/layout.js @@ -11,9 +11,7 @@ export const metadata = { export default function RootLayout({ children }) { return ( - - {children} - + {children} ); } diff --git a/frontend-next/src/app/login/page.js b/frontend-next/src/app/login/page.js index b0ee5aa..29885e0 100644 --- a/frontend-next/src/app/login/page.js +++ b/frontend-next/src/app/login/page.js @@ -1,66 +1,122 @@ "use client"; import { useForm, Form } from "react-hook-form"; import { useRouter } from "next/navigation"; -import "../globals.css" +import "../globals.css"; // Firebase imports -import {auth} from "../../../firebase-config"; -import { setPersistence, signInWithEmailAndPassword, indexedDBLocalPersistence } from "firebase/auth"; +import { auth } from "../../../firebase-config"; +import { + setPersistence, + signInWithEmailAndPassword, + indexedDBLocalPersistence, +} from "firebase/auth"; function Login() { - var router = useRouter(); - //var { register, handleSubmit } = useForm(); - var { register, control, setError, handleSubmit, formState: { errors, isSubmitting, isSubmitted } } = useForm() + var router = useRouter(); + //var { register, handleSubmit } = useForm(); + var { + register, + control, + setError, + handleSubmit, + formState: { errors, isSubmitting, isSubmitted }, + } = useForm(); - function authenticate(data) { - setPersistence(auth, indexedDBLocalPersistence) - .then(() => { - signInWithEmailAndPassword(auth,data.email,data.password) - .then((userCredential) => { - if (userCredential.user) { - router.push("/app") - } else { - const formError = { type: "server", message: "Username or Password Incorrect" } - // set same error in both: - setError('password', formError) - setError('email', formError) - } - }) - }) - } + function authenticate(data) { + setPersistence(auth, indexedDBLocalPersistence).then(() => { + signInWithEmailAndPassword(auth, data.email, data.password).then( + (userCredential) => { + if (userCredential.user) { + router.push("/app"); + } else { + const formError = { + type: "server", + message: "Username or Password Incorrect", + }; + // set same error in both: + setError("password", formError); + setError("email", formError); + } + } + ); + }); + } - return ( + return ( +
+
-
-
- - - Chat with friends! - -
-

Login

- {(errors.email && errors.password) &&
Invalid Email or Password.
} -
-
-
- -
Need an account? Sign Up
-
-
-
-
+ + + + Chat with friends! +
+

Login

+ {errors.email && errors.password && ( +
+ Invalid Email or Password. +
+ )} +
+ +
+ +
+ +
+ Need an account? Sign Up +
+
+
- ) +
+
+ ); } -export default Login; \ No newline at end of file +export default Login; diff --git a/frontend-next/src/app/onboarding/layout.js b/frontend-next/src/app/onboarding/layout.js index 8e01519..1756fe0 100644 --- a/frontend-next/src/app/onboarding/layout.js +++ b/frontend-next/src/app/onboarding/layout.js @@ -5,15 +5,13 @@ const inter = Inter({ subsets: ["latin"] }); export const metadata = { title: "ChatMaps: Onboarding", - description: "ChatMaps: Social Media for College Students" + description: "ChatMaps: Social Media for College Students", }; export default function RootLayout({ children }) { return ( - - {children} - + {children} ); } diff --git a/frontend-next/src/app/onboarding/page.js b/frontend-next/src/app/onboarding/page.js index 72d80aa..0d994cc 100644 --- a/frontend-next/src/app/onboarding/page.js +++ b/frontend-next/src/app/onboarding/page.js @@ -1,57 +1,75 @@ "use client"; -import "../globals.css" +import "../globals.css"; import { useForm } from "react-hook-form"; import { useRouter } from "next/navigation"; import { ref, set } from "firebase/database"; -import {auth, database} from "../../../firebase-config" -import {onAuthStateChanged} from "firebase/auth" +import { auth, database } from "../../../firebase-config"; +import { onAuthStateChanged } from "firebase/auth"; 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 - } - }) + 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; + } + }); } - - function Onboarding() { - var router = useRouter(); - var { register, handleSubmit } = useForm(); + var router = useRouter(); + var { register, handleSubmit } = useForm(); - function Onboard(data) { - createUser(data) - router.push("/app"); - - } - return ( + function Onboard(data) { + createUser(data); + router.push("/app"); + } + return ( +
+
-
-
- - - Chat with friends! - -
- Welcome to ChatMaps! We are excited to have you join our community!
First we just need a little bit of information from you to get started. -
-
-
-
-
- -
-
-
+ + Chat with friends! +
+ Welcome to ChatMaps! We are excited to have you join our community! +
+ First we just need a little bit of information from you to get + started. +
+
+ +
+ +
+ +
+ +
- ) +
+
+ ); } -export default Onboarding; \ No newline at end of file +export default Onboarding; diff --git a/frontend-next/src/app/page.js b/frontend-next/src/app/page.js index 1f88fb0..4cdce00 100644 --- a/frontend-next/src/app/page.js +++ b/frontend-next/src/app/page.js @@ -1,73 +1,99 @@ -"use client" -import { useState, useEffect } from 'react' +"use client"; +import { useState, useEffect } from "react"; import { auth, database } from "../../firebase-config"; -import { ref, get} from "firebase/database"; -import {onAuthStateChanged} from "firebase/auth" - +import { ref, get } from "firebase/database"; +import { onAuthStateChanged } from "firebase/auth"; function Home() { - const [isLoadingLoc, setLoadingLoc] = useState(true) - const [roomCount, setRoomCount] = useState(null) - const [isAuthenticated, setAuth] = useState(false) - const [userID, setUserID] = useState(null) + const [isLoadingLoc, setLoadingLoc] = useState(true); + const [roomCount, setRoomCount] = useState(null); + const [isAuthenticated, setAuth] = useState(false); + const [userID, setUserID] = useState(null); - // Authentication + // Authentication useEffect(() => { onAuthStateChanged(auth, (user) => { if (user) { - setUserID(user.uid) - setAuth(true) + setUserID(user.uid); + setAuth(true); } else { - setAuth(false) + setAuth(false); } - }) - }, []) + }); + }, []); - useEffect(() => { - if('geolocation' in navigator) { - // Retrieve latitude & longitude coordinates from `navigator.geolocation` Web API - navigator.geolocation.getCurrentPosition(({ coords }) => { - var path = String(coords.latitude.toFixed(2)).replace(".","")+"/"+String(coords.longitude.toFixed(2)).replace(".","") - get(ref(database, `/rooms/${path}`)).then((snapshot) => { - if (snapshot.exists()) { - var count = 0 - for (var room in snapshot.val()) { - count += 1 - } - setRoomCount(count) - } else { - setRoomCount(0) - } - setLoadingLoc(false) - }); - }); + useEffect(() => { + if ("geolocation" in navigator) { + // Retrieve latitude & longitude coordinates from `navigator.geolocation` Web API + navigator.geolocation.getCurrentPosition(({ coords }) => { + var path = + String(coords.latitude.toFixed(2)).replace(".", "") + + "/" + + String(coords.longitude.toFixed(2)).replace(".", ""); + get(ref(database, `/rooms/${path}`)).then((snapshot) => { + if (snapshot.exists()) { + var count = 0; + for (var room in snapshot.val()) { + count += 1; + } + setRoomCount(count); + } else { + setRoomCount(0); } - }) - return ( + setLoadingLoc(false); + }); + }); + } + }); + return ( +
+
-
-
- - - Chat with friends! - -
- {(!isAuthenticated) && -
- - -
- } - {isAuthenticated && } - {(!isLoadingLoc && roomCount == 1) &&
Join others in {roomCount} room near you!
} - {(!isLoadingLoc && roomCount != 1 && roomCount != 0) &&
Join others in {roomCount} rooms near you!
} - {(isLoadingLoc || (roomCount == 0 && !isLoadingLoc)) &&
Start the conversation today!
} -
-
-
+ + Chat with friends! +
+ {!isAuthenticated && ( + + )} + {isAuthenticated && ( + + + + )} + {!isLoadingLoc && roomCount == 1 && ( +
+ Join others in {roomCount} room near you! +
+ )} + {!isLoadingLoc && roomCount != 1 && roomCount != 0 && ( +
+ Join others in {roomCount} rooms near you! +
+ )} + {(isLoadingLoc || (roomCount == 0 && !isLoadingLoc)) && ( +
+ Start the conversation today! +
+ )} +
- ) +
+
+ ); } -export default Home; \ No newline at end of file +export default Home; diff --git a/frontend-next/src/app/register/layout.js b/frontend-next/src/app/register/layout.js index c31cd65..4226b89 100644 --- a/frontend-next/src/app/register/layout.js +++ b/frontend-next/src/app/register/layout.js @@ -11,9 +11,7 @@ export const metadata = { export default function RootLayout({ children }) { return ( - - {children} - + {children} ); } diff --git a/frontend-next/src/app/register/page.js b/frontend-next/src/app/register/page.js index 32b1ec8..6aba36d 100644 --- a/frontend-next/src/app/register/page.js +++ b/frontend-next/src/app/register/page.js @@ -1,73 +1,122 @@ "use client"; import { useRouter } from "next/navigation"; import { useForm, Form } from "react-hook-form"; -import "../globals.css" +import "../globals.css"; import { useState } from "react"; -import { createUserWithEmailAndPassword, signInWithEmailAndPassword, setPersistence, indexedDBLocalPersistence } from "firebase/auth"; -import {auth} from "../../../firebase-config"; +import { + createUserWithEmailAndPassword, + signInWithEmailAndPassword, + setPersistence, + indexedDBLocalPersistence, +} from "firebase/auth"; +import { auth } from "../../../firebase-config"; async function Signup(data) { - var userCredential = await createUserWithEmailAndPassword(auth,data.email,data.password); - if (userCredential.user) { - setPersistence(auth, indexedDBLocalPersistence ) - .then(() => { - signInWithEmailAndPassword(auth,data.email,data.password) - .then((res) => { - return true - }) - }) - - } else { - return false - } + var userCredential = await createUserWithEmailAndPassword( + auth, + data.email, + data.password + ); + if (userCredential.user) { + setPersistence(auth, indexedDBLocalPersistence).then(() => { + signInWithEmailAndPassword(auth, data.email, data.password).then( + (res) => { + return true; + } + ); + }); + } else { + return false; + } } function Register() { - var router = useRouter(); - var { register, control, formState: { errors } } = useForm() - var emailRegex = /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/ - var [passwordMismatch, setPasswordMismatch] = useState(false); - const passwordMatch = (data) => { - return data.password === data.passwordCheck; - }; + var router = useRouter(); + var { + register, + control, + formState: { errors }, + } = useForm(); + var emailRegex = + /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/; + var [passwordMismatch, setPasswordMismatch] = useState(false); + const passwordMatch = (data) => { + return data.password === data.passwordCheck; + }; - function onSubmit({data}) { - if (passwordMatch(data)) { - setPasswordMismatch(false); - if (Signup(data)) { - router.push("/onboarding"); - } - - } else{ - setPasswordMismatch(true); - return; - } + function onSubmit({ data }) { + if (passwordMatch(data)) { + setPasswordMismatch(false); + if (Signup(data)) { + router.push("/onboarding"); + } + } else { + setPasswordMismatch(true); + return; } + } - return ( + return ( +
+
-
-
- - - Chat with friends! - -
-

Register

-
-
-
-
- {passwordMismatch &&

Passwords do not match

} -
- Have an account? Log In -
-
-
-
+ + + + Chat with friends! +
+

Register

+
+ +
+ +
+ +
+ {passwordMismatch && ( +

Passwords do not match

+ )} + +
+ Have an account? Log In +
+
- ) +
+
+ ); } export default Register; diff --git a/frontend-next/src/app/user/[stub]/layout.js b/frontend-next/src/app/user/[stub]/layout.js index 94d85e5..778c9bf 100644 --- a/frontend-next/src/app/user/[stub]/layout.js +++ b/frontend-next/src/app/user/[stub]/layout.js @@ -11,9 +11,7 @@ export const metadata = { export default function RootLayout({ children }) { return ( - - {children} - + {children} ); } diff --git a/frontend-next/src/app/user/[stub]/page.js b/frontend-next/src/app/user/[stub]/page.js index d161d90..846f641 100644 --- a/frontend-next/src/app/user/[stub]/page.js +++ b/frontend-next/src/app/user/[stub]/page.js @@ -2,108 +2,89 @@ // System Imports import { useState, useEffect } from "react"; import { auth, database, storage } from "../../../../firebase-config"; -import { ref, onValue, get, update } from "firebase/database"; -import { ref as sRef, getDownloadURL } from "firebase/storage"; -import {onAuthStateChanged} from "firebase/auth" -import { useForm, Form } from "react-hook-form"; +import { ref, onValue, get, update } from "firebase/database"; +import { onAuthStateChanged } from "firebase/auth"; // Refactored Component Imports + // Data Structure Imports - import { Interest, ProfileRoom } from "../../../components/app/datatypes"; +import { ProfileRoom } from "../../../components/app/profile/ProfileRoom"; +import { ProfileEdit } from "../../../components/app/profile/ProfileEdit"; +import { Interest } from "../../../components/app/profile/Interest"; // Header Import import { Header } from "../../../components/app/header"; -import { uploadBytes } from "firebase/storage"; -// Contains most everything for the app homepage -function Home({ params }) { +// User Profile Page +function UserProfile({ params }) { // It's time to document and change these awful variable names // State variables for app page - const [profileData, setProfileData] = useState(null) - const [isAuthenticated, setAuth] = useState(false) - const [user, setUser] = useState(null) - const [userInterestArray, setUserInterestArray] = useState(null) - const [userRoomsArray, setUserRoomsArray] = useState(null) - const [isOwner, setOwn] = useState(false) - const [isEditing, setEdit] = useState(false) + const [profileData, setProfileData] = useState(null); + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [user, setUser] = useState(null); + const [userInterestArray, setUserInterestArray] = useState(null); // Array of user's interests + const [userRoomsArray, setUserRoomsArray] = useState(null); // Array of user's rooms + const [isOwner, setIsOwner] = useState(false); // Determines if user is owner of profile - var { register, control} = useForm() + // Handles Edit State in Component, shares useState with ProfileEdit + const [isEditing, setIsEditing] = useState(false); + const handleIsEditing = (newValue) => { + setIsEditing(newValue); + }; // Authentication useEffect(() => { onAuthStateChanged(auth, (user) => { if (user) { - get(ref(database, `users/${user.uid}`)) - .then((userData) => { - userData = userData.val() + get(ref(database, `users/${user.uid}`)).then((userData) => { + userData = userData.val(); if (userData) { if (userData.uid == params.stub) { - setOwn(true) + setIsOwner(true); } - setUser(userData) - setAuth(true) + setUser(userData); + setIsAuthenticated(true); } else { - window.location.href = "/onboarding" + window.location.href = "/onboarding"; } - - }) + }); } else { - setAuth(false) - window.location.href = "/login" + setIsAuthenticated(false); + window.location.href = "/login"; } - }) - }, []) + }); + }, []); // Grabs profile user data useEffect(() => { - onValue(ref(database, "/users/" + params.stub), (snapshot) => { - setProfileData(snapshot.val()); - var interests = snapshot.val().interests || null; - interests = interests.split(","); - var interestArray = [] - var i = 0 - for (var interest in interests) { - if (i < 4) - interestArray.push() - i++; - } - setUserInterestArray(interestArray) - var rooms = snapshot.val().rooms; - var roomArray = [] - for (var room in rooms) { - roomArray.push() - } - setUserRoomsArray(roomArray); - }); - },[]); + onValue(ref(database, "/users/" + params.stub), (snapshot) => { + setProfileData(snapshot.val()); - function save({data}) { - if (data.pfp[0]) { - // image stuff - uploadBytes(sRef(storage, `users/${user.uid}/pfp`), data.pfp[0]).then(() => { - getDownloadURL(sRef(storage, `users/${user.uid}/pfp`)).then((url) => { - data.pfp = url - for (var key in data) { - if (data[key] == "") { - data[key] = profileData[key] - } - } - - setEdit(false) - update(ref(database, `users/${user.uid}`), data) - }) - }) - } else { - for (var key in data) { - if (data[key] == "") { - data[key] = profileData[key] - } + // Populates array with user's interests + var interests = snapshot.val().interests || null; + if (interests == null) { + // Placeholder for no interests specified, will be replaced with default interests + interests = "Music, Sports, Movies"; } - data.pfp = profileData.pfp - setEdit(false) - update(ref(database, `users/${user.uid}`), data) - } - } + interests = interests.split(","); + var interestArray = []; + var i = 0; + for (var interest in interests) { + if (i < 4) + interestArray.push(); + i++; + } + setUserInterestArray(interestArray); + + // Populates array with user's rooms + var rooms = snapshot.val().rooms; + var roomArray = []; + for (var room in rooms) { + roomArray.push(); + } + setUserRoomsArray(roomArray); + }); + }, []); return (
@@ -112,67 +93,50 @@ function Home({ params }) { {/* Left Side of Page */}
{/* Header */} -
+
{/* Main Page Section */}
-
{!isEditing && (
- +
- {profileData.firstName} {profileData.lastName} + {profileData.firstName} {profileData.lastName}
@{profileData.username}
{profileData.bio}
- {userInterestArray} + {userInterestArray}
)} {isEditing && ( -
-
-
-
- - Current Profile Picture -
-
- -
-
-
-
-
First Name
- -
-
-
Last Name
- -
-
-
Username
- -
-
-
Interests (Comma Seperated)
- -
-
-
Bio
-