diff --git a/backend/models/userModel.js b/backend/models/userModel.js index 7d8f97b..42790ff 100644 --- a/backend/models/userModel.js +++ b/backend/models/userModel.js @@ -1,50 +1,73 @@ -const mongoose=require('mongoose'); -const bcrypt=require('bcryptjs'); -const axios=require('axios') +const mongoose = require("mongoose"); +const bcrypt = require("bcryptjs"); +const axios = require("axios"); -const userSchema=new mongoose.Schema({ - name:{type:String,required:true}, - email:{type:String,required:true,unique:true}, - password:{type:String,required:true}, - pic: { - type:String, - required: true, - default: - "https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg", - }, - isAdmin: { - type: Boolean, - required: true, - default: false, - }, - gender:{ - type:String, - } -}) +const userSchema = new mongoose.Schema({ + name: { type: String, required: true }, + email: { type: String, required: true, unique: true }, + password: { type: String, required: true }, + pic: { + type: String, + required: true, + default: + "https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg", + }, + isAdmin: { + type: Boolean, + required: true, + default: false, + }, + isOnline: { + type: Boolean, + default: false, + }, + lastOnline: { + type: Date, + default: null, + }, + gender: { + type: String, + }, +}); -userSchema.pre('save',async function(next) { - this.password=await bcrypt.hash(this.password,12); - this.passwordConfirm=undefined +userSchema.pre("save", async function (next) { + this.password = await bcrypt.hash(this.password, 12); + this.passwordConfirm = undefined; - let value=await axios.get(`https://api.genderize.io?name=${this.name.split(' ')[0]}`) - this.gender=value.data.gender; + let value = await axios.get( + `https://api.genderize.io?name=${this.name.split(" ")[0]}` + ); + this.gender = value.data.gender; - const menImgList=['https://i.ibb.co/d2qRfFh/9434619.jpg','https://i.ibb.co/GF5K0Zx/9439678.jpg','https://i.ibb.co/LQvJbv1/27470334-7309681.jpg']; - const womenImgList=['https://i.ibb.co/4fSJHhf/27470349-7309670.jpg','https://i.ibb.co/KrCfzc3/27470336-7294793.jpg','https://i.ibb.co/WHQPSRX/7309700.jpg'] + const menImgList = [ + "https://i.ibb.co/d2qRfFh/9434619.jpg", + "https://i.ibb.co/GF5K0Zx/9439678.jpg", + "https://i.ibb.co/LQvJbv1/27470334-7309681.jpg", + ]; + const womenImgList = [ + "https://i.ibb.co/4fSJHhf/27470349-7309670.jpg", + "https://i.ibb.co/KrCfzc3/27470336-7294793.jpg", + "https://i.ibb.co/WHQPSRX/7309700.jpg", + ]; - let randomNumber = Math.floor((Math.random() * 3)); - if(this.pic==='https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg') - { - this.pic=this.gender==='male'?menImgList[randomNumber]:womenImgList[randomNumber] - } + let randomNumber = Math.floor(Math.random() * 3); + if ( + this.pic === + "https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg" + ) { + this.pic = + this.gender === "male" + ? menImgList[randomNumber] + : womenImgList[randomNumber]; + } }); +userSchema.methods.correctPassword = async function ( + passwordDB, + typedPassword +) { + return await bcrypt.compare(typedPassword, passwordDB); +}; -userSchema.methods.correctPassword=async function(passwordDB,typedPassword) -{ - return await bcrypt.compare(typedPassword,passwordDB); -} - - -const User=mongoose.model('User',userSchema); -module.exports=User; \ No newline at end of file +const User = mongoose.model("User", userSchema); +module.exports = User; diff --git a/backend/node_modules/.package-lock.json b/backend/node_modules/.package-lock.json index 68a6b71..c4bb0c7 100644 --- a/backend/node_modules/.package-lock.json +++ b/backend/node_modules/.package-lock.json @@ -993,6 +993,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, "node_modules/mongodb": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.1.4.tgz", diff --git a/backend/package-lock.json b/backend/package-lock.json index acb822c..434dd76 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -16,6 +16,7 @@ "dotenv": "^16.3.1", "express": "^4.18.2", "jsonwebtoken": "^9.0.1", + "moment": "^2.30.1", "mongodb": "4.1", "mongoose": "^7.6.11", "multer": "^1.4.5-lts.1", @@ -1025,6 +1026,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, "node_modules/mongodb": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.1.4.tgz", @@ -2573,6 +2582,11 @@ "minimist": "^1.2.6" } }, + "moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" + }, "mongodb": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.1.4.tgz", diff --git a/backend/package.json b/backend/package.json index 44f32f4..ded6766 100644 --- a/backend/package.json +++ b/backend/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "node server.js" + "start": "nodemon server.js" }, "author": "Samarth Kadam", "license": "ISC", @@ -17,6 +17,7 @@ "dotenv": "^16.3.1", "express": "^4.18.2", "jsonwebtoken": "^9.0.1", + "moment": "^2.30.1", "mongodb": "4.1", "mongoose": "^7.6.11", "multer": "^1.4.5-lts.1", diff --git a/backend/server.js b/backend/server.js index f02bb26..07fc86e 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,89 +1,115 @@ -const express = require('express'); +const express = require("express"); // const app = express(); -const http = require('http'); -const mongoose=require('mongoose'); -const dotenv=require('dotenv'); -const app=require('./app'); -dotenv.config({path:'./config.env'}); -const DBAuth=process.env.DB.replace('',process.env.DBpassword); - -mongoose.connect(DBAuth,{ -useUnifiedTopology: true -}).then((con)=>{ +const http = require("http"); +const mongoose = require("mongoose"); +const moment = require("moment"); +const User = require("./models/userModel"); +const dotenv = require("dotenv"); +const app = require("./app"); + +dotenv.config({ path: "./config.env" }); +const DBAuth = process.env.DB.replace("", process.env.DBpassword); + +mongoose + .connect(DBAuth, { + useUnifiedTopology: true, + }) + .then((con) => { console.log("DB connection successful"); -}) - -process.on('unhandledRejection',err=>{ - console.log(err.name,err.message); - console.log("Unhandled rejection"); -}) - -const port=process.env.PORT; - -const server=app.listen(port,()=>{ - console.log(`SERVER RUNNING IN PORTNO:${port}`); -}) - - - - - - - - - - - - - - + }); +process.on("unhandledRejection", (err) => { + console.log(err.name, err.message); + console.log("Unhandled rejection"); +}); +const port = process.env.PORT; +const server = app.listen(port, () => { + console.log(`SERVER RUNNING IN PORTNO:${port}`); +}); -const io = require('socket.io')(server, { +const io = require("socket.io")(server, { cors: { - origin: ['https://chat-box-samarthkadam.vercel.app','http://localhost:3000'], - } + origin: [ + "https://chat-box-samarthkadam.vercel.app", + "http://localhost:3000", + ], + }, }); -io.on('connection', (socket) => { +io.on("connection", (socket) => { + socket.on("setup", async (userData) => { + socket.userId = userData._id; + await User.findByIdAndUpdate(socket.userId, { + isOnline: true, + lastOnline: null, + }); + socket.join(userData._id); + socket.emit("connected"); + io.emit("status update", { + userId: socket.userId, + isOnline: true, + lastOnline: null, + }); + }); + + socket.on("disconnect", async () => { + if (socket.userId) { + const lastOnline = moment().toISOString(); + await User.findByIdAndUpdate(socket.userId, { + isOnline: false, + lastOnline, + }); + io.emit("status update", { + userId: socket.userId, + isOnline: false, + lastOnline, + }); + } + }); - - socket.on("setup", (userData) => { - console.log("a user connected"); - socket.join(userData._id); - socket.emit("connected"); + socket.on("logout", async () => { + if (socket.userId) { + const lastOnline = moment().toISOString(); + await User.findByIdAndUpdate(socket.userId, { + isOnline: false, + lastOnline, + }); + io.emit("status update", { + userId: socket.userId, + isOnline: false, + lastOnline, }); + socket.userId = null; + socket.emit("server processed logout..!"); + } + }); socket.on("join chat", (room) => { socket.join(room); console.log("User Joined Room: " + room); }); - socket.on("typing",(room)=>{ - socket.to(room).emit("typing",room) - }) - socket.on("stop typing",(room)=>socket.to(room).emit("stop typing",room)); - - - socket.on("removechatbar-send",(chatId)=>{ - - console.log('remove chat bar for this id',chatId); - socket.to(chatId).emit("removechatbar-recieve",chatId) - }) - - socket.on("new message",(newMessageRecieved)=>{ - var chat=newMessageRecieved.chat; + socket.on("typing", (room) => { + socket.to(room).emit("typing", room); + }); + socket.on("stop typing", (room) => socket.to(room).emit("stop typing", room)); - if(!chat.users)return chat.users("users not defined"); + socket.on("removechatbar-send", (chatId) => { + console.log("remove chat bar for this id", chatId); + socket.to(chatId).emit("removechatbar-recieve", chatId); + }); - chat.users.forEach((user)=>{ - if(user._id===newMessageRecieved.sender._id)return; + socket.on("new message", (newMessageRecieved) => { + var chat = newMessageRecieved.chat; - socket.in(user._id).emit('message recieved',newMessageRecieved); - }) - }) + if (!chat.users) return chat.users("users not defined"); + chat.users.forEach((user) => { + if (user._id === newMessageRecieved.sender._id) return; + socket.in(user._id).emit("message recieved", newMessageRecieved); + }); + }); }); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 961e96d..134c703 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -23,6 +23,7 @@ "emoji-mart": "^5.6.0", "gender-detection-from-name": "^1.8.0", "jwt-decode": "^3.1.2", + "moment": "^2.30.1", "randomcolor": "^0.6.2", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -13068,6 +13069,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -27878,6 +27887,11 @@ "minimist": "^1.2.6" } }, + "moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 65da325..76647b7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,6 +18,7 @@ "emoji-mart": "^5.6.0", "gender-detection-from-name": "^1.8.0", "jwt-decode": "^3.1.2", + "moment": "^2.30.1", "randomcolor": "^0.6.2", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/frontend/src/App.js b/frontend/src/App.js index eb5b42d..5bf8b18 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1,19 +1,15 @@ -import './input.css' -import { - createBrowserRouter, - RouterProvider, -} from "react-router-dom"; -import Home from './pages/Home'; -import Service from './pages/Service'; -import Login,{action as LoginAction}from './pages/Login'; -import Signup,{action as SignupAction} from './pages/Signup'; -import HomeChat from './pages/HomeChat'; -import Info from './pages/Info'; -import Settings from './pages/Settings'; - -import Root,{loader as loadingAction} from './pages/Root'; -import Search from './pages/Search'; +import "./input.css"; +import { createBrowserRouter, RouterProvider } from "react-router-dom"; +import Home from "./pages/Home"; +import Service from "./pages/Service"; +import Login, { action as LoginAction } from "./pages/Login"; +import Signup, { action as SignupAction } from "./pages/Signup"; +import HomeChat from "./pages/HomeChat"; +import Info from "./pages/Info"; +import Settings from "./pages/Settings"; +import Root, { loader as loadingAction } from "./pages/Root"; +import Search from "./pages/Search"; const router = createBrowserRouter([ { @@ -21,53 +17,51 @@ const router = createBrowserRouter([ element: , }, { - path:'service', - element: + path: "service", + element: , }, { - path:'login', - element:, - action:LoginAction + path: "login", + element: , + action: LoginAction, }, { - path:'signup', - element:, - action:SignupAction + path: "signup", + element: , + action: SignupAction, }, { - path:'home', - element:, - loader:loadingAction, - children:[ + path: "home", + element: , + loader: loadingAction, + children: [ { - path:'message', - element: + path: "message", + element: , }, { - path:'dashboard', - element: + path: "dashboard", + element: , }, { - path:"settings", - element: + path: "settings", + element: , }, { - path:"search", - element: - } - ] - - } + path: "search", + element: , + }, + ], + }, ]); function App() { - return (); + return ; } export default App; - -///todo +///todo //messages not incoming when ad is showw //responsiveness //loading spinner -// \ No newline at end of file +// diff --git a/frontend/src/components/ChatComponents/ChatBar.js b/frontend/src/components/ChatComponents/ChatBar.js index 8489fb4..5a96d93 100644 --- a/frontend/src/components/ChatComponents/ChatBar.js +++ b/frontend/src/components/ChatComponents/ChatBar.js @@ -1,52 +1,96 @@ -import React from 'react' -import { Avatar } from '@mui/material' -import Badge from '../ChatComponents/util/Badge' -import { getSender } from '../../helper/Reusable' -import { useSelector } from 'react-redux' -import groupLogo from '../../assets/images/group.png' +import React, { useEffect, useState } from "react"; +import { Avatar } from "@mui/material"; +import Badge from "../ChatComponents/util/Badge"; +import { getSender } from "../../helper/Reusable"; +import { useSelector } from "react-redux"; +import { socket } from "../../socket/socket"; +import groupLogo from "../../assets/images/group.png"; -export default function ChatBar({data,select}) { - - const val=useSelector((state)=>state.chat.activeChat); - const isGroupChat=data.isGroupChat; +export default function ChatBar({ data, select }) { + const val = useSelector((state) => state.chat.activeChat); + const isGroupChat = data.isGroupChat; let user; - if(isGroupChat) - { - user={name:data.chatName} - } - else{ - user=getSender(data.users); + if (isGroupChat) { + user = { name: data.chatName }; + } else { + user = getSender(data.users); } - const latestMessage=data.latestMessage?data.latestMessage.content.slice(0,35):''; - let isExcedding=false; - if(data.latestMessage&&data.latestMessage.content.length>35) - isExcedding=true; + const [userStatus, setUserStatus] = useState({ + isOnline: user.isOnline, + lastOnline: user.lastOnline, + }); + + useEffect(() => { + const statusUpdateHandler = (statusUpdate) => { + if (!isGroupChat && statusUpdate.userId === user._id) { + setUserStatus({ + isOnline: statusUpdate.isOnline, + lastOnline: statusUpdate.lastOnline, + }); + } + }; + + socket.on("status update", statusUpdateHandler); + + return () => { + socket.off("status update", statusUpdateHandler); + }; + }, [user._id, isGroupChat]); - - const dateObject = new Date(data.updatedAt); + const latestMessage = data.latestMessage + ? data.latestMessage.content.slice(0, 35) + : ""; + let isExcedding = false; + if (data.latestMessage && data.latestMessage.content.length > 35) + isExcedding = true; + const dateObject = new Date(data.updatedAt); return ( -
-
- -
-
{user.name}
-
{latestMessage}{isExcedding?'.....':''}
-
-
-
-
{`${String(dateObject.getHours()%12).padStart(2,'0')}:${String(dateObject.getMinutes()).padStart(2,'0')} ${dateObject.getHours()>=12?'PM':'AM'}`}
-
- {data.notify&&1} +
+
+ +
+
{user.name}
+
+ {latestMessage} + {isExcedding ? "....." : ""} +
-
- ) +
+ {userStatus.isOnline && ( +
+ )} +
{`${String( + dateObject.getHours() % 12 + ).padStart(2, "0")}:${String(dateObject.getMinutes()).padStart( + 2, + "0" + )} ${dateObject.getHours() >= 12 ? "PM" : "AM"}`}
+
{data.notify && 1}
+
+
+ ); } diff --git a/frontend/src/components/ChatComponents/ChatDetails.js b/frontend/src/components/ChatComponents/ChatDetails.js index 393caa6..6947bc3 100644 --- a/frontend/src/components/ChatComponents/ChatDetails.js +++ b/frontend/src/components/ChatComponents/ChatDetails.js @@ -23,13 +23,12 @@ import { NullifyActiveChat } from "../../services/Actions/Chat/action"; import { removeChat } from "../../services/Actions/Chat/action"; import { socket } from "../../socket/socket"; - const style = { position: "absolute", top: "50%", left: "50%", transform: "translate(-50%, -50%)", - width: window.innerWidth/3, + width: window.innerWidth / 3, bgcolor: "background.paper", boxShadow: 24, borderRadius: "14px", @@ -122,14 +121,17 @@ export default function ChatDetails({ chatModel, closeChat }) { chatName: ref.current.value, }; - const response = await fetch(`${process.env.REACT_APP_API_URL}/api/v1/chat/rename`, { - method: "put", - headers: { - "Content-type": "application/json", - Authorization: `Bearer ${cookie}`, - }, - body: JSON.stringify(bodyData), - }); + const response = await fetch( + `${process.env.REACT_APP_API_URL}/api/v1/chat/rename`, + { + method: "put", + headers: { + "Content-type": "application/json", + Authorization: `Bearer ${cookie}`, + }, + body: JSON.stringify(bodyData), + } + ); const data = await response.json(); if (data.status === "success") { closeChat(); @@ -153,14 +155,17 @@ export default function ChatDetails({ chatModel, closeChat }) { return notify("error", "User already in the group!"); } - const response = await fetch(`${process.env.REACT_APP_API_URL}/api/v1/chat/groupadd`, { - method: "put", - headers: { - "Content-type": "application/json", - Authorization: `Bearer ${cookie}`, - }, - body: JSON.stringify(bodyData), - }); + const response = await fetch( + `${process.env.REACT_APP_API_URL}/api/v1/chat/groupadd`, + { + method: "put", + headers: { + "Content-type": "application/json", + Authorization: `Bearer ${cookie}`, + }, + body: JSON.stringify(bodyData), + } + ); const data = await response.json(); if (data.status === "success") { dispatch(addNewUserToGroup(user, activeUser._id)); @@ -213,7 +218,7 @@ export default function ChatDetails({ chatModel, closeChat }) { body: JSON.stringify(bodyData), } ); - socket.emit("removechatbar-send",activeUser._id) + socket.emit("removechatbar-send", activeUser._id); dispatch(NullifyActiveChat()); dispatch(removeChat(activeUser._id)); // const data=await response.json(); diff --git a/frontend/src/components/ChatComponents/ChatMessages.js b/frontend/src/components/ChatComponents/ChatMessages.js index 296edd6..ef4a6ec 100644 --- a/frontend/src/components/ChatComponents/ChatMessages.js +++ b/frontend/src/components/ChatComponents/ChatMessages.js @@ -37,10 +37,11 @@ export default function ChatMessages() { ); console.log("Lets test"); - if (!isChatBarPresent) - { + if (!isChatBarPresent) { dispatch(addIncomingUserChatBar(newMessageRecieved.chat)); - dispatch(updateChatBar(newMessageRecieved.chat._id, newMessageRecieved.content)); + dispatch( + updateChatBar(newMessageRecieved.chat._id, newMessageRecieved.content) + ); return; } @@ -111,7 +112,7 @@ export default function ChatMessages() { }, [data]); if (isSet === null) return ; - + console.log(data); return (
state.chat.activeChat); const [isTyping, setIsTyping] = useState(false); + const [userStatus, setUserStatus] = useState(null); useEffect(() => { if (data === null) return; + const setTypeHandler = (room) => { + setIsTyping(data._id === room); + }; - const setTypeHandler=(room)=>{ - setIsTyping(data._id===room) - } - - const unsetTypeHandler=(room)=>{ + const unsetTypeHandler = (room) => { setIsTyping(false); - } - + }; - socket.on("typing", setTypeHandler); - socket.on("stop typing",unsetTypeHandler); + const statusUpdateHandler = (statusUpdate) => { + if (data && !data.isGroupChat && statusUpdate.userId === user._id) { + setUserStatus(statusUpdate); + } + }; - return ()=>{ - socket.off("typing",setTypeHandler); - socket.off("stop typing",unsetTypeHandler); - } + socket.on("typing", setTypeHandler); + socket.on("stop typing", unsetTypeHandler); + socket.on("status update", statusUpdateHandler); + return () => { + socket.off("typing", setTypeHandler); + socket.off("stop typing", unsetTypeHandler); + socket.off("status update", statusUpdateHandler); + }; }, [data]); if (data === null) return <>; @@ -43,6 +50,8 @@ export default function ChatTitle({ openChatModel }) { user = getSender(data.users); } + const currentStatus = userStatus || user; + return (
@@ -50,7 +59,13 @@ export default function ChatTitle({ openChatModel }) { referrerPolicy="no-referrer" alt="Group-pic" sx={{ width: 48, height: 48 }} - src={isGroupChat?groupLogo:(user.pic.startsWith('user')?`${process.env.REACT_APP_API_URL}/${user.pic}`:user.pic)} + src={ + isGroupChat + ? groupLogo + : user.pic.startsWith("user") + ? `${process.env.REACT_APP_API_URL}/${user.pic}` + : user.pic + } >
{user.name}
@@ -59,6 +74,14 @@ export default function ChatTitle({ openChatModel }) { {data.isGroupChat ? "Someone" : user.name} is typing...
)} + {!isTyping && + (currentStatus.isOnline ? ( +
+ Online +
+ ) : ( + `Last Online: ${moment(currentStatus.lastOnline).fromNow()}` + ))}
diff --git a/frontend/src/components/RootComponents/UserCard.js b/frontend/src/components/RootComponents/UserCard.js index 98015b5..1489383 100644 --- a/frontend/src/components/RootComponents/UserCard.js +++ b/frontend/src/components/RootComponents/UserCard.js @@ -1,50 +1,59 @@ -import React,{useState} from 'react' -import { Avatar } from '@mui/material' -import { useNavigate } from 'react-router-dom' -import { useSelector } from 'react-redux' -import { useEffect} from 'react' -import {NullifyActiveChat} from '../../services/Actions/Chat/action' -import { useDispatch } from 'react-redux' -import { FlustAllChats } from '../../services/Actions/Chat/action' +import React, { useState } from "react"; +import { Avatar } from "@mui/material"; +import { useNavigate } from "react-router-dom"; +import { useSelector } from "react-redux"; +import { useEffect } from "react"; +import { NullifyActiveChat } from "../../services/Actions/Chat/action"; +import { useDispatch } from "react-redux"; +import { FlustAllChats } from "../../services/Actions/Chat/action"; +import { socket } from "../../socket/socket"; export default function UserCard() { - const dispatch=useDispatch(); - const dataredux=useSelector((state)=>state.user.userInfo) + const dispatch = useDispatch(); + const dataredux = useSelector((state) => state.user.userInfo); - const Obj=JSON.parse(localStorage.getItem('info')) - const [Name,setName]=useState(Obj.name); - const [Pic,setPic]=useState(Obj.pic); - - useEffect(()=>{ - if(dataredux===null) - return; + const Obj = JSON.parse(localStorage.getItem("info")); + const [Name, setName] = useState(Obj.name); + const [Pic, setPic] = useState(Obj.pic); + useEffect(() => { + if (dataredux === null) return; setName(dataredux.name); setPic(dataredux.pic); - },[dataredux]) - + }, [dataredux]); - const navigate=useNavigate(); + const navigate = useNavigate(); - const logoutHandler=()=>{ - localStorage.removeItem('jwt'); - navigate('/',{replace:true}); + const logoutHandler = () => { + socket.emit("logout"); + localStorage.removeItem("jwt"); + navigate("/", { replace: true }); dispatch(NullifyActiveChat()); dispatch(FlustAllChats()); - } - - let image=Pic; - if(Pic.startsWith('user')) - image=`${process.env.REACT_APP_API_URL}/${Pic}` + }; + let image = Pic; + if (Pic.startsWith("user")) image = `${process.env.REACT_APP_API_URL}/${Pic}`; return ( -
- -
-
{Name}
-
Logout
+
+ +
+
+ {Name} +
+
+ Logout
+
- ) + ); } diff --git a/frontend/src/pages/Home.js b/frontend/src/pages/Home.js index 2b7a65a..d353d70 100644 --- a/frontend/src/pages/Home.js +++ b/frontend/src/pages/Home.js @@ -1,49 +1,53 @@ -import React, { useEffect } from 'react' -import NavBar from '../components/HomeComponents/NavBar' -import Description from '../components/HomeComponents/Description' -import Service from './Service' -import { useState } from 'react' -import LoadingPage from './LoadingPage' +import React, { useEffect } from "react"; +import NavBar from "../components/HomeComponents/NavBar"; +import Description from "../components/HomeComponents/Description"; +import Service from "./Service"; +import { useState } from "react"; +import LoadingPage from "./LoadingPage"; -import { useNavigate } from 'react-router-dom' +import { useNavigate } from "react-router-dom"; export default function Home() { + const navigate = useNavigate(); + const [isLoading, setIsLoading] = useState(true); - const navigate=useNavigate(); - const [isLoading,setIsLoading]=useState(true); + useEffect(() => { + const checkIfLoggedIn = async () => { + const cookie = localStorage.getItem("jwt"); + const response = await fetch( + `${process.env.REACT_APP_API_URL}/api/v1/users/protect`, + { + method: "post", + headers: { + "Content-type": "application/json", + Authorization: `Bearer ${cookie}`, + }, + } + ); - useEffect(()=>{ - - const checkIfLoggedIn=async()=>{ - const cookie=localStorage.getItem('jwt'); - const response=await fetch(`${process.env.REACT_APP_API_URL}/api/v1/users/protect`,{ - method:'post', - headers:{ - 'Content-type':'application/json', - 'Authorization':`Bearer ${cookie}` - } - }) - - const data=await response.json(); - if(data.status==='success') - { - navigate('/home/message',{replace:true}) - } - else{ - setIsLoading(false); - } + const data = await response.json(); - } - checkIfLoggedIn() - },[navigate]) + if (data.status === "success") { + localStorage.setItem("userId", data.user._id); + navigate("/home/message", { replace: true }); + } else { + setIsLoading(false); + } + }; + checkIfLoggedIn(); + }, [navigate]); return ( -
- {isLoading&&} - {!isLoading&&(<>
- - -
- )} -
- ) +
+ {isLoading && } + {!isLoading && ( + <> +
+ + +
+ + + )} +
+ ); } diff --git a/frontend/src/pages/HomeChat.js b/frontend/src/pages/HomeChat.js index a652a03..3a72f65 100644 --- a/frontend/src/pages/HomeChat.js +++ b/frontend/src/pages/HomeChat.js @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect } from "react"; import TopBar from "../components/ChatComponents/TopBar"; import ChatBar from "../components/ChatComponents/ChatBar"; import ChatTitle from "../components/ChatComponents/ChatTitle"; @@ -6,7 +6,6 @@ import ChatMessages from "../components/ChatComponents/ChatMessages"; import Type from "../components/ChatComponents/Type"; import { useSelector } from "react-redux"; import { useDispatch } from "react-redux"; -import { useEffect } from "react"; import { useState } from "react"; import { InitializeChat } from "../services/Actions/Chat/action"; import BasicModal from "../components/ChatComponents/BasicModel"; @@ -18,53 +17,59 @@ import NoChats from "./util/NoChats"; import { MotionAnimate } from "react-motion-animate"; import { removeChat } from "../services/Actions/Chat/action"; import { NullifyActiveChat } from "../services/Actions/Chat/action"; + export default function HomeChat() { const state = useSelector((state) => state.chat.AllChats); const dispatch = useDispatch(); + const [token, setToken] = useState(""); + const [users, setUsers] = useState([]); + const [userId, setUserId] = useState(null); const [chatModel, setChatModel] = useState(false); const [isLoading, setIsLoading] = useState(false); - const [requestSent,setRequestSent]=useState(false); - const [isEmpty,setIsEmpty]=useState(false) + const [requestSent, setRequestSent] = useState(false); + const [isEmpty, setIsEmpty] = useState(false); const [open, setOpen] = useState(false); const handleOpen = () => setOpen(true); const handleClose = () => { setOpen(false); }; - - useEffect(()=>{ - const chatfn=(chatid)=>{ - console.log("REmove the chatbar for the id",chatid) + useEffect(() => { + const chatfn = (chatid) => { + console.log("REmove the chatbar for the id", chatid); dispatch(removeChat(chatid)); dispatch(NullifyActiveChat()); - } + }; - socket.on('removechatbar-recieve',chatfn) - return ()=>{ - socket.off('removechatbar',chatfn); - } - },[]) + socket.on("removechatbar-recieve", chatfn); + return () => { + socket.off("removechatbar", chatfn); + }; + }, []); useEffect(() => { const getAllChats = async () => { setIsLoading(true); setRequestSent(true); const cookie = localStorage.getItem("jwt"); - const response = await fetch(`${process.env.REACT_APP_API_URL}/api/v1/chat`, { - headers: { - "Content-type": "application/json", - Authorization: `Bearer ${cookie}`, - }, - }); + const response = await fetch( + `${process.env.REACT_APP_API_URL}/api/v1/chat`, + { + headers: { + "Content-type": "application/json", + Authorization: `Bearer ${cookie}`, + }, + } + ); const data = await response.json(); - if(data.data.length===0) - setIsEmpty(true) - + // console.log(data); + if (data.data.length === 0) setIsEmpty(true); + setToken(cookie); + setUserId(localStorage.getItem("userId")); setIsLoading(false); dispatch(InitializeChat(data.data)); }; - if(state.length>0) - { + if (state.length > 0) { return; } getAllChats(); @@ -86,8 +91,7 @@ export default function HomeChat() { setChatModel(false); }; - - console.log("This is chat state",state); + console.log("This is chat state", state); return (
@@ -100,19 +104,19 @@ export default function HomeChat() {
-
- {isLoading&&} - {!isLoading && - state&& - state.map((data, index) => { - return ( - - - - ); - })} - {isEmpty===true&&state.length === 0 && } -
+
+ {isLoading && } + {!isLoading && + state && + state.map((data, index) => { + return ( + + + + ); + })} + {isEmpty === true && state.length === 0 && } +
diff --git a/frontend/src/socket/socket.js b/frontend/src/socket/socket.js index 9f7a914..2ad1d26 100644 --- a/frontend/src/socket/socket.js +++ b/frontend/src/socket/socket.js @@ -1,3 +1,4 @@ -import { io } from 'socket.io-client'; -const URL =`${process.env.REACT_APP_SOCKET_URL}`; -export const socket = io(URL); \ No newline at end of file +import { io } from "socket.io-client"; +const URL = `${process.env.REACT_APP_SOCKET_URL}`; +// console.log(process.env.REACT_APP_SOCKET_URL); +export const socket = io(URL);