User Profiles V1 (#49)

This commit was merged in pull request #49.
This commit is contained in:
Nicholas Pease
2024-03-28 14:02:00 -04:00
committed by GitHub
17 changed files with 479 additions and 82 deletions
@@ -1,6 +1,7 @@
import { initializeApp, getApps, getApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getDatabase} from "firebase/database"
import {getStorage} from "firebase/storage"
var config = {
apiKey: "AIzaSyDbDPjQGt-lIjNPeTG-Q5AECM1m0vtOr2c",
@@ -14,6 +15,7 @@ var config = {
var app = getApps().length > 0 ? getApp() : initializeApp(config);
var auth = getAuth(app);
var storage = getStorage(app);
var database = getDatabase(app);
export { auth, app, database };
export { auth, app, database, storage };
+42
View File
@@ -8,6 +8,7 @@
"name": "chatmaps",
"version": "0.1.0",
"dependencies": {
"@headlessui/react": "^1.7.18",
"firebase": "^10.6.0",
"next": "^14.1.0",
"pigeon-maps": "^0.21.3",
@@ -627,6 +628,22 @@
"node": ">=6"
}
},
"node_modules/@headlessui/react": {
"version": "1.7.18",
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.18.tgz",
"integrity": "sha512-4i5DOrzwN4qSgNsL4Si61VMkUcWbcSKueUV7sFhpHzQcSShdlHENE5+QBntMSRvHt8NyoFO2AGG8si9lq+w4zQ==",
"dependencies": {
"@tanstack/react-virtual": "^3.0.0-beta.60",
"client-only": "^0.0.1"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"react": "^16 || ^17 || ^18",
"react-dom": "^16 || ^17 || ^18"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.14",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
@@ -1014,6 +1031,31 @@
"tslib": "^2.4.0"
}
},
"node_modules/@tanstack/react-virtual": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.2.0.tgz",
"integrity": "sha512-OEdMByf2hEfDa6XDbGlZN8qO6bTjlNKqjM3im9JG+u3mCL8jALy0T/67oDI001raUUPh1Bdmfn4ZvPOV5knpcg==",
"dependencies": {
"@tanstack/virtual-core": "3.2.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@tanstack/virtual-core": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.2.0.tgz",
"integrity": "sha512-P5XgYoAw/vfW65byBbJQCw+cagdXDT/qH6wmABiLt4v4YBT2q2vqCOhihe+D1Nt325F/S/0Tkv6C5z0Lv+VBQQ==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+1
View File
@@ -9,6 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"@headlessui/react": "^1.7.18",
"firebase": "^10.6.0",
"next": "^14.1.0",
"pigeon-maps": "^0.21.3",
+19 -11
View File
@@ -1,12 +1,12 @@
"use client";
// System Imports
import { useState, useEffect } from "react";
import { auth, database } from "../api/firebase-config";
import { auth, database } from "../../../firebase-config";
import { ref, onValue, set, remove, get } from "firebase/database";
import { useBeforeunload } from "react-beforeunload";
import {useRouter} from "next/navigation";
import {Marker} from "pigeon-maps";
import {onAuthStateChanged, signOut} from "firebase/auth"
import {onAuthStateChanged} from "firebase/auth"
// Refactored Component Imports
// Data Structure Imports
@@ -45,6 +45,19 @@ function Home() {
const [markers, setMarkers] = useState([]);
const [isAuthenticated, setAuth] = useState(false)
const [user, setUser] = useState(null)
const [usingSearchParams, setUsingSearchParams] = useState(true)
useEffect(() => {
const searchParams = new URLSearchParams(document.location.search);
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())
});
}
}, [user])
// Authentication
useEffect(() => {
@@ -53,7 +66,6 @@ function Home() {
get(ref(database, `users/${user.uid}`))
.then((userData) => {
userData = userData.val()
console.log(userData)
if (userData) {
setUser(userData)
setAuth(true)
@@ -69,7 +81,6 @@ function Home() {
})
}, [])
// Grabs user data, saves to user, then lists the users saved rooms
useEffect(() => {
if (user) {
@@ -141,7 +152,6 @@ function Home() {
}
},[user]);
// Dont Double Send Leaving Message
useEffect(() => {
if (myRoomsObj && chatRoomObj) {
@@ -169,6 +179,7 @@ function Home() {
user: user.username,
isSystem: true,
timestamp: new Date().getTime(),
uid: user.uid
};
set(
ref(
@@ -197,10 +208,6 @@ function Home() {
}
// 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")
@@ -225,6 +232,7 @@ function Home() {
user: user.username,
isSystem: true,
timestamp: new Date().getTime(),
uid: user.uid
};
set(
ref(
@@ -278,7 +286,7 @@ function Home() {
<Home_Sidebar tab={tab} nearby={nearby} loadingNearby={loadingNearby} setTab={setTab} isRoomLoading={isRoomLoading} myRooms={myRooms} loadingLoc={loadingLoc} location={location}/>
)}
{mainTab == "chat" && (
<Chat_Sidebar chatRoomObj={chatRoomObj} chatroomOnline={chatroomOnline} chatroomUsersLoading={chatroomUsersLoading} chatroomUsers={chatroomUsers}/>
<Chat_Sidebar chatRoomObj={chatRoomObj} chatroomOnline={chatroomOnline} chatroomUsersLoading={chatroomUsersLoading} chatroomUsers={chatroomUsers} setTab={setTab}/>
)}
{mainTab == "profile" && (
<Profile_Sidebar/>
+4 -4
View File
@@ -4,8 +4,8 @@ import { useRouter } from "next/navigation";
import "../globals.css"
// Firebase imports
import {auth} from "../api/firebase-config";
import { setPersistence, signInWithEmailAndPassword, browserSessionPersistence } from "firebase/auth";
import {auth} from "../../../firebase-config";
import { setPersistence, signInWithEmailAndPassword, indexedDBLocalPersistence } from "firebase/auth";
function Login() {
var router = useRouter();
@@ -13,7 +13,7 @@ function Login() {
var { register, control, setError, handleSubmit, formState: { errors, isSubmitting, isSubmitted } } = useForm()
function authenticate(data) {
setPersistence(auth, browserSessionPersistence)
setPersistence(auth, indexedDBLocalPersistence)
.then(() => {
signInWithEmailAndPassword(auth,data.email,data.password)
.then((userCredential) => {
@@ -45,7 +45,7 @@ function Login() {
>
<input type="email" id="email" className={(errors.email && errors.password) && "err"} {...register("email", { required: true })} placeholder="Enter Email Address"/><br/>
<input type="password" id="password" name="password" className={(errors.email && errors.password) && "err"} {...register("password", { required: true })} placeholder="Enter Password"/><br/>
<button className="inline-flex items-center px-4 py-2 transition ease-in-out duration-150 bg-[#dee0e0] m-5 bg-cyan-500 text-white font-bold py-2 px-4 rounded-full">
<button type="submit" className="inline-flex items-center px-4 py-2 transition ease-in-out duration-150 bg-[#dee0e0] m-5 bg-cyan-500 text-white font-bold py-2 px-4 rounded-full">
{(isSubmitting || isSubmitted) && <span className="inline-block">
<svg class="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" cx="12" cy="12" r="10" strokeWidth="4"></circle>
+1 -2
View File
@@ -3,13 +3,12 @@ import "../globals.css"
import { useForm } from "react-hook-form";
import { useRouter } from "next/navigation";
import { ref, set } from "firebase/database";
import {auth, database} from "../api/firebase-config"
import {auth, database} from "../../../firebase-config"
import {onAuthStateChanged} from "firebase/auth"
function createUser(data) {
onAuthStateChanged(auth, (user) => {
if (user.uid) {
console.log(user)
data.uid = user.uid
data.defined = true
data.email = user.email
+1 -2
View File
@@ -1,7 +1,7 @@
"use client"
import { useState, useEffect } from 'react'
import { auth, database } from "./api/firebase-config";
import { auth, database } from "../../firebase-config";
import { ref, get} from "firebase/database";
import {onAuthStateChanged} from "firebase/auth"
@@ -37,7 +37,6 @@ function Home() {
}
setRoomCount(count)
} else {
console.log("No rooms nearby")
setRoomCount(0)
}
setLoadingLoc(false)
+5 -10
View File
@@ -4,17 +4,16 @@ import { useForm, Form } from "react-hook-form";
import "../globals.css"
import { useState } from "react";
import { createUserWithEmailAndPassword, signInWithEmailAndPassword, setPersistence, browserSessionPersistence } from "firebase/auth";
import {auth} from "../api/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, browserSessionPersistence)
setPersistence(auth, indexedDBLocalPersistence )
.then(() => {
signInWithEmailAndPassword(auth,data.email,data.password)
.then((res) => {
console.log(res)
return true
})
})
@@ -56,16 +55,12 @@ function Register() {
</span>
<div>
<h3 className="text-[24px] mt-[15px]">Register</h3>
<Form onSubmit={onSubmit}
encType={'application/json'}
control={control}
>
<Form onSubmit={onSubmit} encType={'application/json'} control={control}>
<input type="email" {...register("email", {required: true, pattern: emailRegex})} className={errors.email && "err"} placeholder="Enter Email Address"/><br/>
<input type="password" {...register("password", {required: true})} className={errors.password && errors.password.type == 'required' && "err"} placeholder="Enter Password"/><br/>
<input type ="password" {...register("passwordCheck", {required: false})} className ={errors.passwordCheck && errors.passwordCheck.type == 'required' && "err"} placeholder="Re-enter Password"/><br/>
{passwordMismatch && <p className="text-red-500">Passwords do not match</p>}
<button type="submit" className="bg-[#dee0e0] m-5 bg-cyan-500 text-white font-bold py-2 px-4 rounded-full">
Register</button><br/>
<button type="submit" className="bg-[#dee0e0] m-5 bg-cyan-500 text-white font-bold py-2 px-4 rounded-full"> Register</button><br/>
Have an account? <a href="/login">Log In</a>
</Form>
</div>
@@ -0,0 +1,19 @@
import { Inter } from "next/font/google";
import "../../globals.css";
const inter = Inter({ subsets: ["latin"] });
export const metadata = {
title: "ChatMaps: User Profile",
description: "ChatMaps: Social Media for College Students",
};
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>
{children}
</body>
</html>
);
}
+191
View File
@@ -0,0 +1,191 @@
"use client";
// 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";
// Refactored Component Imports
// Data Structure Imports
import { Interest, ProfileRoom } from "../../../components/app/datatypes";
// Header Import
import { Header } from "../../../components/app/header";
import { uploadBytes } from "firebase/storage";
// Contains most everything for the app homepage
function Home({ 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)
var { register, control} = useForm()
// Authentication
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (user) {
get(ref(database, `users/${user.uid}`))
.then((userData) => {
userData = userData.val()
if (userData) {
if (userData.uid == params.stub) {
setOwn(true)
}
setUser(userData)
setAuth(true)
} else {
window.location.href = "/onboarding"
}
})
} else {
setAuth(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(<Interest interest={interests[interest]}/>)
i++;
}
setUserInterestArray(interestArray)
var rooms = snapshot.val().rooms;
var roomArray = []
for (var room in rooms) {
roomArray.push(<ProfileRoom room={rooms[room]}/>)
}
setUserRoomsArray(roomArray);
});
},[]);
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]
}
}
data.pfp = profileData.pfp
setEdit(false)
update(ref(database, `users/${user.uid}`), data)
}
}
return (
<div>
{isAuthenticated && (
<div className="overflow-hidden">
{/* Left Side of Page */}
<div className="h-dvh overflow-hidden">
{/* Header */}
<Header user={user}/>
{/* Main Page Section */}
<div className="grid grid-cols-3 mr-2 h-[calc(100%-110px)] pl-5 pr-5 pt-2">
<div className="cols-span-1 bg-white shadow-2xl rounded-xl pt-5">
{!isEditing && (
<div>
<img src={profileData.pfp} width="300px" className="relative mx-auto rounded-2xl overflow-hidden"/>
<div className="font-bold text-[30px]">
{profileData.firstName} {profileData.lastName}
</div>
<div className="text-[20px]">@{profileData.username}</div>
<div className="pt-5">{profileData.bio}</div>
<div className="grid grid-cols-3 p-3">
{userInterestArray}
</div>
<div className="grid grid-cols-1 auto-cols-min justify-items-center">
{isOwner && ( <a onClick={() => {setEdit(true)}} className="w-[120px] p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full text-center"> Edit Profile </a> )}
{!isOwner && ( <a className="w-[120px] p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full text-center"> Add Friend </a> )}
</div>
</div>
)}
{isEditing && (
<div>
<Form onSubmit={save} encType={'application/json'} control={control}>
<div className="grid grid-cols-2">
<div>
<img src={profileData.pfp} width="150px" className="relative mx-auto rounded-2xl overflow-hidden"/>
Current Profile Picture
</div>
<div className="flex content-center">
<input type="file" {...register("pfp")} className="w-[80%]" accept=".jpg,.png,.jpeg"/>
</div>
</div>
<div className="grid grid-cols-2 pl-2 w-[90%]">
<div className="pt-5">
<div className="font-bold">First Name</div>
<input className="w-[80%] border-2 border-gray-300 p-2 rounded-lg" type="text" {...register("firstName")} placeholder={profileData.firstName}/>
</div>
<div className="pt-5">
<div className="font-bold">Last Name</div>
<input className="w-[80%] border-2 border-gray-300 p-2 rounded-lg" type="text" {...register("lastName")} placeholder={profileData.lastName}/>
</div>
<div className="pt-5">
<div className="font-bold">Username</div>
<input className="w-[80%] border-2 border-gray-300 p-2 rounded-lg" type="text" {...register("username")} placeholder={profileData.username}/>
</div>
<div className="pt-5">
<div className="font-bold">Interests (Comma Seperated)</div>
<input className="w-[80%] border-2 border-gray-300 p-2 rounded-lg" type="text" {...register("interests")} placeholder={profileData.interests}/>
</div>
<div className="pt-5 col-span-2">
<div className="font-bold">Bio</div>
<textarea className="w-[92%] border-2 border-gray-300 p-2 rounded-lg" {...register("bio")} type="text" placeholder={profileData.bio}/>
</div>
<div className="justify-items-center pt-5 col-span-2">
<button type="submit" className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full text-center"> Save Changes </button>
</div>
</div>
</Form>
</div>
)}
</div>
<div className="col-span-2">
<div className="grid grid-cols-3 gap-y-1 pl-5 gap-1 h-[100%] w-[100%]">
{userRoomsArray}
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
}
export default Home;
+53 -31
View File
@@ -17,32 +17,32 @@ const userColors = [
"#c3cb71",
];
let dateOptions = {
weekday: "long",
year: "numeric",
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
};
const generateColor = (user_str) => {
// hashes username for consistent colors, maybe all functionality to pick color later
let hash = 0;
for (let i = 0; i < user_str.length; i++) {
hash = user_str.charCodeAt(i) + (hash * 32 - hash);
}
const index = Math.abs(hash) % userColors.length;
return index;
};
// Chat Message
export function Chat({ chatObj }) {
let dateOptions = {
weekday: "long",
year: "numeric",
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
};
const generateColor = (user_str) => {
// hashes username for consistent colors, maybe all functionality to pick color later
let hash = 0;
for (let i = 0; i < user_str.length; i++) {
hash = user_str.charCodeAt(i) + (hash * 32 - hash);
}
const index = Math.abs(hash) % userColors.length;
return index;
};
return (
<div className="width-[100%] bg-white rounded-lg mt-1 text-left p-1 grid grid-cols-2 mr-2">
<div>
<span style={{ color: userColors[generateColor(chatObj.user)] }}>
{chatObj.user}
<a href={chatObj.uid && ("/user/"+chatObj.uid)} className="hover:font-bold cursor-pointer" target="_blank">{chatObj.user}</a>
</span>
: {chatObj.body}
</div>
@@ -55,14 +55,6 @@ export function Chat({ chatObj }) {
// System Chat Message
export function SystemMessage({ chatObj }) {
let dateOptions = {
weekday: "long",
year: "numeric",
month: "short",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
};
const generateColor = (user_str) => {
// hashes username for consistent colors, maybe all functionality to pick color later
@@ -78,7 +70,7 @@ return (
<div className="width-[100%] bg-white rounded-lg mt-1 text-left p-1 grid grid-cols-2 mr-2">
<div className="text-[#d1d1d1]">
<span style={{ color: userColors[generateColor(chatObj.user)] }}>
{chatObj.user}
<a href={chatObj.uid && ("/user/"+chatObj.uid)} className="hover:font-bold cursor-pointer" target="_blank">{chatObj.user}</a>
</span>{" "}
has {chatObj.body} the room.
</div>
@@ -92,9 +84,11 @@ return (
// Member for Active/Room members in sidebar
export function Member({ memberObj }) {
return (
<div className="cursor-pointer g-[aliceblue] rounded-lg m-3 shadow-xl p-2">
<a href={"/user/"+memberObj.uid} target="_blank">
<div className="cursor-pointer g-[aliceblue] rounded-lg m-3 shadow-xl p-2" >
{memberObj.username}
</div>
</a>
);
}
@@ -139,4 +133,32 @@ export function Geo({ loc, zoom, locMarker, markers }) {
<Map className="rounded-lg" defaultCenter={[0, 0]} defaultZoom={zoom} />
);
}
}
}
// Interest for Profile
export function Interest({interest}) {
return (
<div>
<div className="rounded-lg m-2 p-2 shadow-xl">
{interest}
</div>
</div>
)
}
export function ProfileRoom({room}) {
return (
<div className="rounded-lg p-2 shadow-xl bg-white h-[250px] w-[325px]">
<div className="relative z-1 h-[235px] opacity-50">
<Geo loc={{"latitude": room.latitude, "longitude": room.longitude}} zoom={12} locMarker={false}/>
</div>
<div className="relative z-2 top-[-235px] text-left p-2">
<div className="text-2xl font-bold">{room.name}</div>
<div>{room.description}</div>
<div>Created on {new Date(room.timestamp).toLocaleString(dateOptions)}</div>
<a href={"/app?room="+room.path+"/"+room.name+"-"+room.timestamp} className="absolute z-2 top-[190px] w-[108px] p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full flex items-center">Open Room</a>
</div>
</div>
)
}
+34 -17
View File
@@ -1,9 +1,10 @@
import { auth, database } from "../../app/api/firebase-config";
import { auth, database } from "../../../firebase-config";
import { ref, set, remove } from "firebase/database";
import {signOut} from "firebase/auth";
import { Popover } from '@headlessui/react'
function logout() {
console.log("Fire")
signOut(auth)
}
@@ -15,6 +16,7 @@ import {signOut} from "firebase/auth";
user: user.username,
isSystem: true,
timestamp: new Date().getTime(),
uid: user.uid
};
set(
ref(
@@ -74,22 +76,22 @@ import {signOut} from "firebase/auth";
export function Header({mainTab, isMyRoom, chatRoomObj, setChatRoomObj, setMainTab, setIsMyRoom, user}) {
return (
<div className="m-2 rounded-lg h-[63px] bg-white shadow-2xl grid grid-cols-2 p-1">
<div className="h-[60px]">
<a href="/">
<div className="flex m-2 rounded-lg h-[63px] bg-white shadow-2xl p-1">
<div className="flex shrink h-[60px]">
<a href="/app">
<img
src="logos/logo_transparent_inverse.png"
src="/logos/logo_transparent_inverse.png"
className="h-[60px]"
/>
</a>
</div>
<div className="h-[60px] p-4">
<div className="grow grid grid-rows-1 grid-flow-col auto-cols-max justify-end gap-2 h-[60px] p-2">
{mainTab == "chat" && isMyRoom == false && (
<a
onClick={() => {
addToMyRooms(chatRoomObj, setIsMyRoom, user);
}}
className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full mr-5"
className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full mr-5 flex items-center"
>
Add to &quot;My Rooms&quot;
</a>
@@ -99,7 +101,7 @@ export function Header({mainTab, isMyRoom, chatRoomObj, setChatRoomObj, setMainT
onClick={() => {
removeFromMyRooms(chatRoomObj, setIsMyRoom, user);
}}
className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full mr-5"
className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full mr-5 flex items-center"
>
Remove from &quot;My Rooms&quot;
</a>
@@ -109,18 +111,33 @@ export function Header({mainTab, isMyRoom, chatRoomObj, setChatRoomObj, setMainT
onClick={() => {
closeChatRoom(chatRoomObj, setChatRoomObj, setMainTab, user);
}}
className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full mr-5"
className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full mr-5 flex items-center"
>
Close Chat
</a>
)}
<a
onClick={logout}
href="/"
className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full"
>
Sign Out
</a>
<Popover className="relative">
<Popover.Button as="div">
<div className="mr-5 h-[44px] p-[2px] pr-[15px] cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full shadow-2xl flex">
<div className="flex items-center pl-1">
Nicholas
</div>
<div className="ml-3 rounded-lg">
<img src={user.pfp} width="40px" className="relative mx-auto rounded-xl overflow-hidden"/>
</div>
</div>
</Popover.Button>
<Popover.Panel className="absolute z-10 bg-white mt-[4px] rounded-xl ml-3 shadow-2xl">
<div className="grid grid-cols-1">
<a className="rounded-xl p-4 hover:bg-[#C0C0C0]" href={"/user/"+user.uid}>View Profile</a>
<a className="rounded-xl p-4 hover:bg-[#C0C0C0]" onClick={logout} href="/">Sign Out</a>
</div>
<img src="/solutions.jpg" alt="" />
</Popover.Panel>
</Popover>
</div>
</div>
)
@@ -2,7 +2,7 @@ import { Chat, SystemMessage} from "../datatypes"
import { useState, useEffect } from "react";
import { Form, useForm } from "react-hook-form";
import { ref, onValue, set} from "firebase/database";
import { database } from "../../../app/api/firebase-config";
import { database } from "../../../../firebase-config";
// Chatroom Module for Primary Tab
@@ -51,6 +51,7 @@ export function MainTabChatRoom({ roomObj, user }) {
var payload = {
body: data.message,
user: user.username,
uid: user.uid,
isSystem: false,
timestamp: new Date().getTime(),
};
@@ -1,6 +1,6 @@
import { Geo } from "../datatypes";
export function Chat_Sidebar({chatRoomObj, chatroomOnline, chatroomUsersLoading, chatroomUsers}) {
export function Chat_Sidebar({chatRoomObj, chatroomOnline, chatroomUsersLoading, chatroomUsers, setTab}) {
return (
<div className="h-dvh">
<div className="m-2 h-[98%] grid grid-cols-1">
@@ -1,5 +1,5 @@
import { Form, useForm } from "react-hook-form";
import { database } from "../../../app/api/firebase-config";
import { database } from "../../../../firebase-config";
import { ref, set } from "firebase/database";
// CreateRoom Module for Sidebar Create Tab
+97 -1
View File
@@ -2,5 +2,101 @@
"name": "ChatMaps",
"lockfileVersion": 3,
"requires": true,
"packages": {}
"packages": {
"": {
"dependencies": {
"react-router-dom": "^6.22.3"
}
},
"node_modules/@remix-run/router": {
"version": "1.15.3",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz",
"integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"peer": true
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"peer": true,
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/react": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/react-dom": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.0"
},
"peerDependencies": {
"react": "^18.2.0"
}
},
"node_modules/react-router": {
"version": "6.22.3",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz",
"integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==",
"dependencies": {
"@remix-run/router": "1.15.3"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"react": ">=16.8"
}
},
"node_modules/react-router-dom": {
"version": "6.22.3",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz",
"integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==",
"dependencies": {
"@remix-run/router": "1.15.3",
"react-router": "6.22.3"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"react": ">=16.8",
"react-dom": ">=16.8"
}
},
"node_modules/scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
}
}
}
}
+5
View File
@@ -0,0 +1,5 @@
{
"dependencies": {
"react-router-dom": "^6.22.3"
}
}