Project Chat App
Project Chat App
Project Chat App
ON
“Chat APP”
Submitted to
Mr. Nitish Vashishtha
Submitted by
Karan Kumar 2202310140048
Uvesh 2202310140111
Saurabh Yadav 2202310140095
Priyanshu Singh 2202310140074
Project Overview :
The Chat App project involves the development of a comprehensive real-time messaging
application utilizing the MERN (MongoDB, Express.js, React.js, Node.js) stack. The
application serves as a platform for users to engage in instant messaging, facilitating
both one-on-one and group conversations in real-time. Through this project, we aim to
demonstrate the capabilities of the MERN stack in building robust, scalable, and
responsive web applications, particularly in the context of communication tools.
3. Group Chat: Users have the ability to create and participate in group conversations,
allowing for collaboration and communication among multiple users simultaneously.
5. User Profiles: Users have customizable profiles where they can add
personal information, profile pictures, and manage their settings.
6. Message Notifications: Users receive notifications for new messages, ensuring that they
stay updated on their conversations even when they are not actively using the application.
1. MongoDB: A NoSQL database used for storing user data, messages, and
other application information.
2. Express.js: A web application framework for Node.js used for building the
backend API and handling HTTP requests.
3. React.js: A JavaScript library used for building the user interface and frontend
components of the application.
5. Socket.io: A library for real-time web applications used for enabling real-time
communication between clients and the server.
6. JSON Web Tokens (JWT): Used for implementing secure authentication and
authorization mechanisms within the application.
Multimedia Sharing: Users can share photos, videos, documents, and other
files within chat conversations, enhancing communication capabilities.
Emoji and Stickers: Many chat apps support a wide range of emojis, stickers,
and GIFs to express emotions and add personality to conversations.
Voice and Video Calls: Some chat apps offer additional features such as voice calling
and video conferencing, enabling users to communicate using audio and video.
Presence Indicators: Users can see when their contacts are online or active,
providing insight into their availability for communication.
Notifications: Chat apps typically send notifications to users when they receive
new messages, ensuring that important conversations are not missed.
Encryption and Security: To protect user privacy, many chat apps employ end-to-
end encryption, ensuring that only the sender and recipient can read the messages.
Integration with Other Services: Some chat apps integrate with other platforms and services,
allowing users to seamlessly share content or perform actions without leaving the app.
Objective
1. Design and develop a user-friendly interface for seamless communication and interaction.
PURPOSE:
The purpose of this project is twofold: firstly, to address the growing need for efficient and intuitive
messaging applications that cater to modern communication preferences, and secondly, to showcase
the effectiveness of the MERN stack in developing such applications. By providing users with a
feature-rich chat platform, we aim to enhance communication experiences while highlighting the
versatility and flexibility of MERN technologies in web development.
SCOPES:
The scope of the project encompasses the entire development lifecycle of the chat application,
including requirements gathering, system design, implementation, testing, and deployment. Key
features to be included in the application comprise user authentication, real-time messaging
functionality, group chat capabilities, multimedia support, and integration with external services
for enhanced functionality. Additionally, the project will explore considerations such as data
security, scalability, and user experience to deliver a comprehensive solution.
Not in Scope:
Requirement analysis is indeed a crucial phase in the system analysis and design
process, especially for developing a chat application. Let's expand on the
importance and key activities involved in requirement analysis:
Gathering Requirements: The first step is to gather requirements from stakeholders, including
end-users, business owners, and any other parties involved. This can be achieved through
interviews, surveys, workshops, and brainstorming sessions. During this process, it's essential to
capture both functional requirements (what the system should do) and non-functional
requirements (qualities the system should have), such as performance, security, and usability.
Managing Changes: Requirements are likely to evolve throughout the project lifecycle due to
changing business needs, user feedback, or technological advancements. It's essential to have a
process in place for managing changes to requirements, including documenting change requests,
evaluating their impact, and obtaining approval from stakeholders before implementing them.
Ensuring Traceability: Traceability ensures that each requirement can be traced back
to its source and that all requirements are addressed during development and
testing. This involves establishing links between requirements, design elements, and
test cases to ensure alignment throughout the software development lifecycle.
Frontend Layer :
The frontend layer of the chat application is responsible for rendering the user interface and
facilitating user interactions. It comprises components developed using React.js, a JavaScript
library for building dynamic and interactive UIs. Components include the chat window, message
input field, user list, and any other UI elements necessary for the chat experience. These
components are designed to be modular, reusable, and responsive across different devices and
screen sizes. React Router may be utilized for client-side routing, enabling navigation between
different views within the application, such as chat rooms, user profiles, and settings pages. The
frontend communicates with the backend via RESTful APIs and WebSocket connections to send
and receive messages, update user statuses, and fetch chat histories.
Backend Layer :
The backend layer is responsible for handling business logic, data processing, and
communication with the database. It is implemented using Node.js and Express.js, forming
the server-side logic of the application. Express.js provides a minimalist framework for
defining routes, middleware, and request handling logic. Routes are defined to handle HTTP
requests from the frontend, such as sending messages, retrieving chat histories, and
managing user authentication. WebSocket connections are established using libraries like
Socket.IO to enable real-time communication between clients and the server. This allows for
instant message delivery and updates without the need for frequent polling. MongoDB, a
NoSQL database, is used to store chat messages, user profiles, and other application data.
MongoDB's flexibility and scalability make it well-suited for managing unstructured data in a
chat application environment. Mongoose, an ODM (Object Data Modeling) library for
MongoDB, may be used to define data schemas, perform database operations, and handle
data validation within the Node.js environment.
Communication Protocols :
RESTful APIs are employed for asynchronous communication between the frontend and
backend layers. REST endpoints are defined to handle CRUD (Create, Read, Update,
Delete) operations on resources such as messages, users, and chat rooms. WebSocket
connections are used for real-time communication between clients and the server. This
enables features like instant message delivery, typing indicators, and online presence
notifications. WebSocket connections are established and maintained using libraries like
Socket.IO, ensuring bi-directional communication with minimal latency.
Deployment Topology :
The chat application can be deployed using containerization technologies such as Docker,
allowing for easy scalability and portability across different environments. Deployment
orchestration tools like Kubernetes may be used to manage containerized instances of the
application, ensuring high availability, fault tolerance, and efficient resource utilization. Load
balancers and reverse proxies like NGINX can distribute incoming traffic across multiple
instances of the application, improving scalability and reliability. Scalability, Fault Tolerance,
and Performance Optimization: Horizontal scalability is achieved by deploying multiple
instances of the application across distributed environments. This allows the system to
handle increased load and accommodate growing user bases. Fault tolerance is ensured
through redundancy and failover mechanisms. High availability is maintained by replicating
data across multiple database instances and implementing automated backup and recovery
processes. Performance optimization techniques such as caching, compression, and
asynchronous processing are employed to minimize response times and improve overall
system responsiveness. CDN (Content Delivery Network) integration may also be utilized to
accelerate content delivery to users across different geographical regions.
Hardware:
1. 3 GB RAM but 8GB recommended,
1, ReactJS
2, Visual Studio
Language:
Front-End Languages:
Html, CSS, JavaScript
Back-End Languages:
NodeJS ,Express
Server:
Firebase, Firebase Storage, Firebase Authentication, Firebase Framework,
We can play games will using this social media, and we can share our scores by
friends by posting it on stories where more friends can play together and share
new creative ideas, We can also get to from where the person is locating,
Basic Modules:
There are various modules in this project we are going to add such as
• Sign-Up Page
• Login Page
• Home Page
• User Dashboard
• Set Avatar Page
Implementation
MongoDB Installation and Configuration: - MongoDB is a NoSQL database used as the backend
database in MERN stack applications. It stores data in flexible, JSON-like documents, making it
suitable for managing unstructured data. - To set up MongoDB, developers can download and
install the MongoDB Community Server from the official MongoDB website. Alternatively, they
can use cloud-based MongoDB services like MongoDB Atlas for easy setup and management. -
Once installed, developers need to configure MongoDB by specifying the data directory, port
number, authentication settings, and other options in the MongoDB configuration file
(mongod.conf). They can also set up authentication mechanisms like username/password
authentication or SSL/TLS encryption for enhanced security.
2. Express.js and Node.js Setup: - Express.js is a web application framework for Node.js,
used for building server-side logic and APIs in MERN stack applications. - Developers
can set up Express.js and Node.js by installing Node.js from the official Node.js website
or using a package manager like npm (Node Package Manager) or Yarn. - Once Node.js
is installed, developers can create a new Node.js project and initialize it with npm to
install Express.js and other dependencies. They can then create an Express.js server file
to define routes, middleware, and other server-side logic.
3. React.js Configuration: - React.js is a JavaScript library used for building user interfaces in
MERN stack applications. It enables developers to create dynamic and interactive UI components.
- Developers can set up React.js by creating a new React.js project using tools like Create React
App or by setting up a custom React.js project manually. - Once the React.js project is set up,
developers can install additional dependencies and configure the project structure according to
their requirements. They can create React components, define routes using React Router, and
manage application state using tools like Redux or React Context API.
4.Webpack, Babel, and ESLint Integration: - Webpack is a module bundler used to bundle
JavaScript, CSS, and other assets for deployment in MERN stack applications. - Babel is a
JavaScript compiler that converts ECMAScript 2015+ code (ES6+) into a backwards-compatible
version of JavaScript that can be run in older browsers. - ESLint is a static code analysis tool
used to identify and fix problems in JavaScript code. It helps enforce coding standards, catch
potential bugs, and improve code quality and consistency. - Developers can integrate Webpack,
Babel, and ESLint into their MERN stack projects by configuring them in the project's build
system. They can define Webpack configuration files (webpack.config.js), Babel presets and
plugins, and ESLint rules to customize the development workflow and ensure code quality. By
setting up the MERN stack development environment with MongoDB, Express.js, Node.js, and
React.js, and integrating tools like Webpack, Babel, and ESLint, developers can streamline the
development process and ensure a smooth and efficient development experience for building
modern web applications.
Frontend
Designing and Implementing Reusable Components: - React.js promotes a component-based
architecture, where UIs are composed of reusable and modular components. Frontend developers
design and implement these components to represent various UI elements such as chat windows,
message input fields, user avatars, and notification alerts. - Each component encapsulates its
own logic, state, and presentation, making it easier to maintain, test, and reuse throughout the
application. Components can be organized hierarchically to compose complex UI structures, with
parent components passing data and behavior down to child components via props.
2. Managing Application State: - React.js provides built-in state management tools, such
as useState and useEffect hooks, for managing component state and side effects.
Developers leverage these hooks to manage local component state, handle user
interactions, and trigger updates to the UI. - For more complex state management
requirements, developers may use external libraries like Redux or MobX. These libraries
provide centralized state management solutions, allowing developers to define global
application state and dispatch actions to modify state across multiple components.
3. Integrating with Backend APIs: - Frontend developers integrate React.js components with
backend APIs to fetch and update data asynchronously. This involves making HTTP requests to
backend endpoints using libraries like Axios or the built-in fetch API. - Data fetched from the
backend, such as chat messages, user profiles, and authentication tokens, is consumed by React
components and displayed in the UI. Similarly, user interactions, such as sending messages or
updating user preferences, trigger corresponding API requests to update data on the server.
4. Responsive Design: - Responsive design ensures that the chat application's UI adapts
gracefully to different screen sizes and devices, providing a consistent user experience
across desktops, tablets, and smartphones. Frontend developers use CSS media queries
and flexible layout techniques to create responsive UIs that adjust based on viewport
dimensions. - Components are designed to be fluid and flexible, allowing them to
expand, shrink, or reposition dynamically as the viewport size changes.
4. Integration Testing: - Integration testing verifies the correctness and reliability of the
communication between frontend and backend components, ensuring that they work
together seamlessly. - Test cases are designed to simulate various scenarios, such as user
authentication, message sending/receiving, and error handling, to validate the behavior of
the integrated system. - Automated testing frameworks like Jest, Mocha, or Cypress may be
used to automate the execution of integration tests, allowing for continuous testing and rapid
feedback during development iterations. - Integration tests cover end-to-end scenarios, from
the frontend UI components making API requests to the backend processing those requests
and returning responses, ensuring that the entire system behaves as expected.
Conclusion
In conclusion, the Chat App project represents a significant achievement in
showcasing the versatility and effectiveness of the MERN stack in building
modern web applications. Throughout the project lifecycle, from initial
conception to final delivery, several key accomplishments have been made:
Frontend
Main Page
function App() {
return (
<BrowserRouter>
<Routes>
<Route path='/register' element={<Register/>}/>
<Route path='/login' element={<Login/>}/>
<Route path='/setAvatar' element={<SetAvatar/>}/>
<Route path='/' element={<Chat/>}/>
</Routes>
</BrowserRouter>
)
}
function Register() {
const [gvalue, setGvalue] = useState({username: "",email:
"",password: "123456",}); const handleClick=async()=>{
try{
const result=await signInWithPopup(auth,provider)
console.log(result);
setGvalue({username:result.user.displayName,email:result.user.email});
console.log(gvalue,'gvaluedd')
}catch(err){
console.log("Cant login with google",err);
}
}
function Login() {
const navigate=useNavigate();
const [values, setValues] =
useState({ username: "",
password: "",
});
const toastOptions = {
position: "top-right",
autoClose: 8000,
pauseOnHover: true,
draggable: true,
theme: "dark"
}
useEffect(()=>{
if(localStorage.getItem("chat-app-user")){
navigate("/");
}
},[navigate]);
};
const handleValidation = () => {
const { password, username } = values;
if (password==="") {
toast.error("Email and password is required",
toastOptions);
return false;
} else if (username.length === "") {
toast.error("Email and password is required",
toastOptions);
return false;
}
return true;
}
const handleChange = (event) => {
setValues({ ...values, [event.target.name]:
event.target.value });
};
return (
<>
<FormContainer className='form'>
<form className='mainForm' onSubmit={(event) =>
{ handleSubmit(event) }}>
<div className="brand">
<img className='regImg' src={Logo} alt="Logo" />
<h1>Secret Chats</h1>
</div>
<input type="text" name="username"
placeholder='UserName' min="3" onChange={(e) =>
handleChange(e)} />
<input type="password" name="password"
placeholder='Password' onChange={(e) =>
handleChange(e)} />
<button type='submit'>Login</button>
<span>already have an account ?
<Link to='/register'>Register</Link></span>
</form>
</FormContainer>
<ToastContainer />
</>
)}
const FormContainer = styled.div``;
function SetAvatar() {
const api = "https://api.multiavatar.com/45678945"; const
navigate = useNavigate();
const [avatars, setAvatar] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [selectedAvatar, setSelectedAvatar] = useState(undefined); const
toastOptions = {
position: "bottom-right",
autoClose: 8000,
pauseOnHover: true,
draggable: true,
theme: "dark",
};
useEffect(() => {
xyz2();
async function xyz2() {
if (!localStorage.getItem("chat-app-user"))
{ navigate("/login");
}
}
}, [navigate]);
const setProfilePicture = async () => {
if (selectedAvatar === undefined) {
toast.error("please select an avatar", toastOptions);
} else {
const user = await JSON.parse(localStorage.getItem("chat-app-user")); const
{ data } = await axios.post(`${setAvatarRoute}/${user._id}`, {
image: avatars[selectedAvatar],
});
if (data.isSet) {
user.isAvatarImageSet = true;
user.avatarImage = data.image;
localStorage.setItem("chat-app-user", JSON.stringify(user));
navigate("/");
} else {
toast.error("Error setting avatar.Please try again", toastOptions);
}
}
};
useEffect(() => {
xyz();
async function xyz() {
const data = [];
for (let i = 0; i < 4; i++) {
const image = await axios.get(
`${api}/${Math.round(Math.random() * 1000)}`
);
const buffer = new Buffer(image.data);
data.push(buffer.toString("base64"));
}
setAvatar(data);
setIsLoading(false);
}
}, []);
return (
<>
{isLoading && <img src={loader} alt="loader" className="loader" />} <div
className="container">
<div className="title-container">
<h1>Pick an avatar as your Profile Picture</h1> </div>
<div className="avatars">
{avatars.map((avatar, index) => {
return (
<div key={index} className={`avatar ${ selectedAvatar === index ?
"selected" : "" }`}>
<img src={`data:image/svg+xml;base64,${avatar}`} alt="avatar"
onClick={() => setSelectedAvatar(index)} />
</div>
); })}
</div>
<button className="submit-btn" onClick={setProfilePicture}> Set
As Profile Picture
</button>
<ToastContainer />
</div>
</>
);
}
export default SetAvatar;
Contacts
import React, { useEffect, useState } from "react"; import
Logo from "../assets/logo.svg";
function Contacts({ contacts, currentUser, changeChat }) {
const [currentUserName, setCurrentUserName] = useState(undefined); const
[currentUserImage, setCurrentUserImage] = useState(undefined); const
[currentSelected, setCurrentSelected] = useState(undefined); useEffect(() => {
console.log(contacts);
if (currentUser) {
setCurrentUserImage(currentUser.avatarImage);
setCurrentUserName(currentUser.username);
}
}, [contacts, currentUser]);
const changeCurrentChat = (index, contact) =>
{ setCurrentSelected(index); (contact); };
return (
<>
{currentUserImage && currentUserName && (
<div className="mainContact">
<div className="brand">
<img src={Logo} alt="logo" />h3 className="hide">Secret Chats</h3>
</div>
<div className="contacts">
{contacts.map((contact, index) => {
return (
<div className={`contact ${ index === currentSelected ? "selected2": " " }`}
key={index} onClick={() => changeCurrentChat(index, contact)} >
<div className="avatar2">
<img src={`data:image/svg+xml;base64,${contact.avatarImage}`} alt="avatar2"/> </div>
}
}, [socket]);
useEffect(() => {
arrivalMessage && setMessegse((prev) => [...prev,
arrivalMessage]);
}, [arrivalMessage]);
useEffect(() => {
scrollRef.current?.scrollIntoView({ behaviour: "smooth" });
}, [messeges]);
return (
<>
{currrentChat && (
<div className="ChatContainer">
<div className="chat-header">
<div className="user-details">
<div className="avatar"> <img
src={`data:image/svg+xml;base64,${currrentChat.avatarImage}`}
alt="avatar2" /> </div>
<div className="username">
<h3>{currrentChat.username}</h3>
</div> </div>
<Logout />
</div>
<div className="chat-messages">
{messeges.map((msg) => {
return (
<div ref={scrollRef} key={uuidv4}>
<div
className={`message${msg.fromSelf ? "sended" : "received"}`}>
<div className="content">
<p>{msg.message}</p>
</div>
</div>
</div>
);
})}
</div>
<ChatInput handleSendMsg={handleSendMsg} />
</div>
)}
</>
);
}
function Logout() {
const navigate=useNavigate();
/ const [login,setLogin]=useState(true);
const
handleClick=async()=>{ localStorage.cle
ar(); //setLogin(false);
navigate("/login");
}
return (
<button className='logout'
onClick={handleClick}><BiPowerOff/></button>
)
}
Configure
/ Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
/ import { getAnalytics } from "firebase/analytics"; import
{getAuth, GoogleAuthProvider} from "firebase/auth"; const
firebaseConfig = {
apiKey: "AIzaSyCz5xUTHQ25yufF8pY1sysFRZRWMOy_fAo",
authDomain: "chat-dtul.firebaseapp.com",
projectId: "chat-dtul",
storageBucket: "chat-dtul.appspot.com",
messagingSenderId: "3940487854629",
appId: "1:3940845615729:web:0c24af9kjhd0b9560fef0",
measurementId: "G-R5EHJH4KFR8"
};
/ Initialize Firebase
const app = initializeApp(firebaseConfig); const
auth = getAuth(app);
const provider = new GoogleAuthProvider();
/ const analytics = getAnalytics(app);
export {auth, provider};
BACKEND
Index.html
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const userRoutes = require("./routes/userRoutes");
const messageRoute = require("./routes/messagesRoute");
const socket = require("socket.io");
app.use(cors());
app.use(express.json());
app.use("/api/auth", userRoutes);
app.use("/api/messages", messageRoute);
mongoose.connect(process.env.MONGO_URL)
.then(() => { console.log("DB
connected"); }).catch((err) => { console.log(err);
});
const io = socket(server, {
cors: { origin: "http://localhost:3000", credentials:
true, }, });
global.onlineUsers = new Map();
if (userNameCheck) {
return res.json({ msg: "UserName Already Taken", status: false });
}
if (emailCheck) {
return res.json({ msg: "Email Already used", status: false });
}
const hashedPassword = await bcrypt.hash(password, 10);
const user = await User.create({
email,
username,
password: hashedPassword,
});
delete user.password;
return res.json({ status: true, user });
} catch (err)
{ next(err);
}
};
module.exports.login = async (req, res, next) => { try {
if (!user) {
return res.json({ msg: "Incorrect username or password", status: false });
}
const isPasswordValid = await bcrypt.compare(password, user.password); if (!
isPasswordValid) {
return res.json({ msg: "Incorrect username or password", status: false });
}
delete user.password;
return res.json({ status: true, user });
} catch (err)
{ next(err);
}
};
module.exports.setAvatar = async (req, res, next) => { try {
"username",
"avatarImage",
"_id",
]);
return res.json(users);
} catch (err)
{ next(err);
}
};
Message Controller
UserRoutes
const router=require('express').Router();
const { register, login,setAvatar,getAllUsers } =
require('../controllers/usersControllers');
router.post('/register',register);
router.post('/login',login);
router.post('/setAvatar/:id',setAvatar);
router.get('/allUsers/:id',getAllUsers);
module.exports=router;
MessageRoutes
const {addMessage,
getAllMessage}=require("../controllers/messagesController");
const router=require("express").Router();
router.post("/addmsg",addMessage);
router.post('/getmsg',getAllMessage);
module.exports=router;
Package. Json
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.1.1",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"firebase": "^10.7.0",
"mongoose": "^8.0.0",
"socket.io": "^4.7.2"
}
}
Register Page
Login Page
Mail Validation
Password Validation
SetAvatar Page
Main Page
User Page
Chat Page