Compare commits
35 Commits
sgoodridge-edit
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ea77d8941 | |||
| 33f42a703a | |||
| 0db13e3178 | |||
| aeb28b0623 | |||
| 0ac733fa63 | |||
| e7f0855578 | |||
| 0f9a74826a | |||
| 67b8725f70 | |||
| b9e244cf03 | |||
| 4a5078cab3 | |||
| 29de0c85fe | |||
| 77c2bf9620 | |||
| 91735beb88 | |||
| f02e74bc3a | |||
| c3361e3141 | |||
| 0cf510e95c | |||
| 754442adfa | |||
| 833361255b | |||
| 7a231c4e39 | |||
| 08c88fb59c | |||
| 4b5454ddc2 | |||
| 623de2877e | |||
| ce6b23ec98 | |||
| a83f219c02 | |||
| 97325623fe | |||
| 19466dd98f | |||
| 577dddd785 | |||
| a58579e753 | |||
| f5f4706123 | |||
| 0886b85847 | |||
| 30a40bf6b1 | |||
| ae927dea0d | |||
| 69d2b98d50 | |||
| ceaabd3514 | |||
| 94513bb0d9 |
@@ -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
|
||||
@@ -11,6 +11,14 @@ The live version of this app can be found at:
|
||||
|
||||
https://chatma.ps/
|
||||
|
||||
Demo Login:<br/>
|
||||
Email: demo@chatma.ps<br/>
|
||||
Password: demoapp<br/>
|
||||
|
||||
Please note. The demo is restricted to sending messages, and creating rooms. This is intented to ensure the demo remains an adequate example of the functionalities of this application. If you would like to test the full set of features, please make an account.
|
||||
|
||||
|
||||
|
||||
A local version can be run (assuming you have Node installed) with:
|
||||
|
||||
cd frontend-next/
|
||||
@@ -23,3 +31,5 @@ then navigating to:
|
||||
|
||||
http://localhost:3000
|
||||
|
||||
NOTICE: Access to firebase from localhost has been disabled due to security considerations. To demo our app, please go to https://chatma.ps!
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+3304
-1525
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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,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) {
|
||||
|
||||
@@ -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,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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user