B2 Project Report

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 120

CHATROOM HUB

A PROJECT REPORT
Submitted
In partial fulfillment of the requirements for
the award of the degree of
BACHELOR OF TECHNOLOGY
in
INFORMATION TECHNOLOGY
by
K.Sai Rashmika [20B01A1290] M.Geethika [20B01A1296]
Reddy Ramya

M.Srijitha Devi [20B01A12B2] M.Praneetha [20B01A12B3]


Devi

Under the Guidance of

P. Venkata Rama Raju

Associate Professor

DEPARTMENT OF INFORMATION TECHNOLOGY


SHRI VISHNU ENGINEERING COLLEGE FOR WOMEN
(AUTONOMOUS)
BHIMAVARAM – 534 202, INDIA
2020-24
SHRI VISHNU ENGINEERING COLLEGE FOR WOMEN
(AUTONOMOUS)
BHIMAVARAM – 534 202
DEPARTMENT OF INFORMATION TECHNOLOGY

DECLARATION

I therefore pronounce that the work depicted in this project report


entitled “Chatroom Hub” which is being presented by us in partial fulfillment
for the award of Degree of Bachelor of Technology in the Department of
Information Technology to the Shri Vishnu Engineering College for Women,
Bhimavaram, is the consequences of investigations completed by us under
the supervision of “Dr. P. Venkata Rama Raju” Department of IT, SVECW.

The work is unique and has not been submitted to a limited extent or
full for the honor of any Degree in any other University or Institute.

NAME REGD NO SIGNATURE


K. Sai Rashmika Reddy 20B01A1290 K. S. Rashmika
M. Geethika Ramya 20B01A1296 M. G. Ramya
M. Srijitha Devi 20B01A12B2 M. Srijitha
M. Praneetha Devi 20B01A12B3 M. Praneetha

Place: Bhimavaram
Date:
SHRI VISHNU ENGINEERING COLLEGE FOR WOMEN
(AUTONOMOUS)
BHIMAVARAM – 534 202
DEPARTMENT OF INFORMATION TECHNOLOGY

CERTIFICATE

This is to certify that the Project Report entitled “CHATROOM HUB” that
is being submitted by K. SAI RASHMIKA REDDY [ 20B01A1290], M.
GEETHIKA RAMYA [20B01A1296], M. SRIJITHA DEVI [20B01A12B2], M.
PRANEETHA DEVI [20B01A12B3] in partial fulfillment for the award of
Bachelor of Technology in Information Technology to the Shri Vishnu
Engineering College for Women, Bhimavaram is a record of bonafide work did by
them under my supervision during the academic year 2020 - 24.

To the best of my insight, the work consolidated in this postulation has not been
submitted somewhere else for the honor of any degree.

Internal Guide Head of the Department,


Dr. P. Venkata Rama Raju Department of IT,
Associate Professor SVECW.
Department of IT,
SVECW.

External Examiner
DECLARATION

This project work entitled “CHATROOM HUB” has been carried out by us in the partial fulfillment of the
requirements for the award of the degree of B. Tech (IT), Shri Vishnu Engineering College for Women. I
hereby declare that this project work/ project report has not been submitted to any other University/ Institute
for the award of any other degree/ diploma.

Project Associates:

K. SAI RASHMIKA REDDY [20B01A1290]


M. GEETHIKA RAMYA [20B01A1296]
M. SRIJITHA DEVI [20B01A12B2]
M. PRANEETHA DEVI [20B01A12B3]
ACKNOWLEDGEMENTS

Behind every achievement lies an unfathomable sea of gratitude to those who


activated it, without whom it would never ever come into existence. To them
we lay a word of gratitude imprinted within us.

We wish to place our deep sense of gratitude to Sri. K. V. Vishnu Raju, Chairman
of SVECW for his constant support on our each and every progressive work.

We are thankful to Dr. G. Srinivasa Rao, Principal of SVECW, for being a


source of inspiration and constant encouragement.

We wish to express our sincere thanks to Dr. P. Srinivasa Raju, Vice-Principal


of SVECW, for being a source of inspiration and constant encouragement.

We wish to express our sincere thanks to our Dr. D. Venkata Naga Raju, Head
of the Department of Information Technology of SVECW, for his valuable advice
in completing this project successfully.

We wish to thank our guide Dr. P. Venkata Rama Raju for his unflinching
devotion and valuable suggestions to complete our main project successfully in
time.

Project Associates

K. SAI RASHMIKA REDDY - [20B01A1290]

M. GEETHIKA RAMYA - [20B01A1296]

M. SRIJITHA DEVI - [20B01A12B2]

M. PRANEETHA DEVI - [20B01A12B3]


TABLE OF CONTENTS
ABSTRACT.....................................................................................................................i
LIST OF FIGURES......................................................................................................ii
LIST OF TABLES........................................................................................................iv
Chapter 1. INTRODUCTION........................................................................................1
Chapter 2. SYSTEM ANALYSIS..................................................................................3
2.1 Existing System..................................................................................................3
2.2 Proposed System.................................................................................................3
2.3 Feasibility Study.................................................................................................5
Chapter 3. SYSTEM REQUIREMENT SPECIFICATION.......................................6
3.1 System Specification..........................................................................................6
3.2 Requirement Specification.................................................................................7
3.3 Technology.........................................................................................................7
3.3.1 ReactJS......................................................................................................7
3.3.2 Firebase.....................................................................................................8
Chapter 4. SYSTEM DESIGN.....................................................................................13
4.1 Database Design................................................................................................14
4.2 UML Diagrams..................................................................................................15
Chapter 5. SYSTEM TESTING..................................................................................19
5.1 Introduction........................................................................................................19
5.2 Types of Testing................................................................................................19
5.3 Test Cases..........................................................................................................21
Chapter 6. LAYOUT DESIGNS..................................................................................22
Chapter 7. CONCLUSION AND FUTURE WORK.................................................31
Chapter 8. REFERENCES...........................................................................................32
Chapter 9. APPENDIX.................................................................................................33
9.1 Sample Code......................................................................................................33
ABSTRACT

The Chatroom Hub project introduces a dynamic and user-centric approach to

online communication. This innovative web-based application empowers users to

create customized chatrooms tailored to their diverse communication needs,

ensuring that every interaction is a reflection of their unique interests. Users have

the liberty to create an unlimited number of chatrooms, making it a versatile

platform for both personal and professional use.

The Chatroom Hub offers a comprehensive range of functionalities like a feature

provides flexible control over connections, streamlining the management of their

chatroom engagements.

The technology stack powering the Chatroom Hub comprises ReactJS for a

responsive and intuitive user interface, Firebase for real-time data management, and

SCSS for enhanced styling. This combination of technologies ensures a seamless

and feature-rich user experience, making the Chatroom Hub a game-changer in the

world of online communication.

The Chatroom Hub project introduces a user experience that is deeply customizable

and engaging. It brings together state-of-the-art technologies and a user-centric

design to redefine the way people connect and communicate online.

i
LIST OF FIGURES
Figure No. & Description Page No

2.1 System Architecture 4

3.1 Firebase Dashboard 9

3.2 Collections inside the database 10

3.3 JSON Structure 10

3.4 Authentication 11

3.5 Firebase Storage 11-12

3.5.1 Profiles folder


6.7 Uploading new avatar 25
3.5.2 Storing avatars
16
4.1 Use case Diagram
6.8 Displaying foravatar
updated Chatroom hub 25

4.2 Class diagram for the application 17


6.9 Changing nickname 26

4.3 Sequence diagram for the application 18


6.10 Display of created chatrooms and chats 26

6.1 Welcome page 22


6.11 Liking a message 27
6.2 Google signup page 22
6.12 Deleting a message 27
6.3 Login Page 23
6.13 Editing room details 28
6.4 Successful signup alert 23

6.14 Showing updated room details 28


6.5 User Dashboard 24

6.15 Making other


6.6 Updating members as admin
username 29
24

6.16 Dialog box while uploading files 29

6.17 Selecting and Uploading files ii 30

6.18 Final View of chatroom after uploading files 30


LIST OF FIGURES

ii
i
LIST OF TABLES

Table No & Description Page No

5.3.1 Test Cases for Chatroom Application 21

iv
CHATROOM HUB

1. INTRODUCTION

In the digital realm, chatroom hubs emerge as dynamic centers of interaction and
community, embodying the essence of connectivity in the modern age. These platforms
offer a virtual haven where individuals from diverse backgrounds converge to share ideas,
seek advice, and forge meaningful connections. Serving as digital town squares, chatroom
hubs accommodate a myriad of interests and discussions, from niche hobbies to global
issues, transcending geographical boundaries and cultural barriers.

Within these vibrant spaces, users find solace in the anonymity afforded by screen names,
enabling authentic expression and fostering mutual respect. Chatroom hubs catalyze
innovation and collaboration, serving as incubators for new ideas and collective
intelligence. Through lively debates, brainstorming sessions, and collaborative projects,
participants harness the power of community to address complex problems and drive
positive change.

Moreover, the relationships formed within chatroom hubs often extend beyond the digital
realm, shaping real-world experiences and connections. As participants engage in
spontaneous conversations and deliberate exchanges, they cultivate a sense of belonging
and empowerment, reaffirming the intrinsic human need for connection and camaraderie
in virtual spaces. In essence, chatroom hubs epitomize the transformative potential of
online communities, where every keystroke holds the promise of insight, connection, and
shared humanity.

System Modules

 User Authentication

 Chatroom Creation

 Real Time Messaging

 User Profiles

User Authentication

A user authentication module verifies the identity of individuals accessing a system or


application. It typically requires users to provide credentials such as usernames and
passwords, which are compared against stored records in a database. Advanced
authentication methods may include biometric data or two-factor authentication for
enhanced security. The module ensures that only authorized users can access protected
resources, safeguarding sensitive information and preventing unauthorized access.
Through encryption and secure protocols, it protects user data from interception or
manipulation. User authentication modules are essential components of secure systems,
enforcing access controls and preserving the integrity of digital environments.

Chatroom Creation

A chatroom creation module facilitates the establishment of virtual spaces for real-time

Dept of Information Technology, SVECW Page 1


CHATROOM HUB

communication among users. It enables administrators or users with appropriate privileges


to create chatrooms with designated names, topics, and access permissions. Users can join
these chatrooms to engage in discussions, share multimedia content, and exchange
messages. The module typically includes features for managing participant lists,
moderating conversations, and enforcing community guidelines. It may offer
customization options for chatroom appearance and functionality, allowing users to tailor
the experience to their preferences. By providing a platform for interaction and
collaboration, the chatroom creation module fosters community building and facilitates
the exchange of ideas in digital environments.

Real Time Messaging

A real-time messaging module enables instantaneous communication between users


across digital platforms. It utilizes protocols such as WebSocket or HTTP Long Polling to
facilitate immediate message delivery and receipt. Users can exchange text, multimedia
content, and interactive elements in a seamless manner, fostering dynamic conversations
and collaboration. The module supports features like message threading, notifications, and
read receipts to enhance user experience and engagement. It often includes robust security
measures such as encryption and authentication to safeguard messages and user privacy.
Real-time messaging modules are integral components of modern applications, enabling
swift and efficient communication in various contexts, from social networking to business
collaboration.

User profiles

A user profiles module centralizes and manages information about individuals within a
digital system or application. It allows users to create, update, and customize their profiles
with personal details, preferences, and settings. These profiles often include user-
generated content, such as biographical information, profile pictures. The module may
offer privacy controls for users to manage the visibility of their profiles and control access
to specific information. The user profiles module serves as a cornerstone for
personalization and community building within digital platforms.

Dept of Information Technology, SVECW Page 2


CHATROOM HUB

2. SYSTEM ANALYSIS

System analysis is an important activity that’s takes place when we are building a
new system or changing the existing one. Analysis helps to understand the existing
system and requirements necessary for building the new system. If there is no existing
system then analysis defines only the requirements.

One of the most important factors in the system analysis is to understand the
system and its problems. A good understanding of the system enables designer to identify
and correct problems. Based on the drawbacks of existing system is being planned. So the
total definition of the given problem has been analyzed.

2.1 Existing System

 Users have limited flexibility to create chatrooms tailored to their specific


requirements
 Users miss out on the convenience of connecting through their preferred social
media accounts, potentially resulting in a less streamlined and integrated
communication experience.

Drawbacks

 Due to limited flexibility, This lack of customization hinders users from organizing
and participating in discussions that align precisely with their interests, potentially
resulting in less engagement.
 The absence of integration with popular platforms like Google and Facebook in the
existing system can be a drawback.

2.2 Proposed System

 In this Application, Users can create an unlimited number of chatrooms, providing


flexibility for tailored discussions, promoting engagement, and enhancing
personalization.
 Users can connect to their Google and Facebook accounts, streamlining the
registration and login process while enhancing user convenience.
 The Chatroom Hub offers a user-friendly dashboard that simplifies the
management of connections and chatrooms, making it easier for users to organize
their online interactions.
 The platform enables the seamless sharing of documents, videos, images, and
audio recordings, making communication rich and diverse with features like
change or upload an avatar, message notifications.

Dept of Information Technology, SVECW Page 3


CHATROOM HUB

Advantages

 This application creates new chatrooms and send text messages, images, and
audio clips.
 It shows the status of other users whether he/she is online (or) offline and users
can like or delete the messages.
 Chatroom Hub implement admin controls in chatrooms, such as the ability to add
or remove permissions.
 This Interface allows users to change or upload their avatar. And to make the
application responsive.

Chat room provides


Chooses respective Can edit user details different features like
User opens the link of Signs up by using account and enters like name, avatar.. and User status, admin Logs out of the
the application. Facebook or Google. into the chat can create new chat permissions, sharing application
application. rooms. Multi-media files and
notification settings.

Fig 2.1 System Architecture

The System Architecture is represented in fig 2.1. Initially the user will open the
application link by logging or signing in by using their Email or Facebook or Google
accounts. The User can either successfully logs into their respective account or gets an
error alert for incorrect approach. Then the User will enter into the application. The user
can edit their details like Name, avatar, and can create new chat rooms and this
information will be stored in our Realtime database. Chat room provides different
features like User status, admin permissions, sharing multi-media files and notification
settings and the users can log out of their application after completing their respective
tasks.

Dept of Information Technology, SVECW Page 4


CHATROOM HUB

2.3 Feasibility Study


It defines whether an application is technically, operationally and economically
feasible.

Types of Feasibilities

1. Technical Feasibility
2. Operational Feasibility
3. Economical Feasibility

Technical Feasibility
The system is technically feasible as we have implemented this application using
technologies like Android Studio, Firebase, and One Signal which have many inbuilt
features for developing an application.

Operational Feasibility
The system is operationally feasible as we can access this application from any
location irrespective of place and time.

Economical Feasibility
The system is economically feasible as it is developed using open sources and
free tools like Android Studio, Firebase, and One Signal which doesn’t require any
maintenance cost.

Detailed Analysis by feasibility study


 Users have limited capacity to develop chatrooms suited to their individual
needs.
 This lack of flexibility makes it difficult for users to organize and participate in
conversations that are specifically relevant to their interests, perhaps leading to
lower participation.
 The lack of connectivity with prominent platforms such as Google and Facebook
in the current system may be a disadvantage.
 Users miss out on the ease of connecting via their chosen social network
accounts, which may result in a less streamlined and integrated communication
experience.

Dept of Information Technology, SVECW Page 5


CHATROOM HUB

3. SYSTEM REQUIREMENT SPECIFICATION

3.1 System Specification


Initially for any application, a client approaches with his/her requirements.
The management approached us with time duration, development cost and
maintenance cost. Then, we discussed with the stake holders and total system is
analyzed and detailed report of the requirements is finalized.

Modules
1. User Authentication
2. Chatroom Creation
3. Real Time Messaging
4. User Profiles

1. User Authentication
 The User Authentication module in the chatroom hub ensures secure access to user
accounts by implementing robust login mechanisms.
 Incorporating Facebook and Gmail authentication into the chatroom hub enables
users to seamlessly log in using their existing Facebook or Gmail credentials.
 It securely stores user credentials using encryption techniques like hashing and
salting to prevent unauthorized access to sensitive information.
 Users can register with unique usernames and strong passwords, with optional multi-
factor authentication for added security layers.
 The module also manages user sessions securely, enforcing session timeouts and
employing HTTPS encryption to protect data during transmission.
2. Chatroom Creation
The chatroom creation module facilitates users in creating new chatrooms within
the platform, offering options to set room names, privacy settings, and invite participants.
Users can specify room topics, access controls, and moderation preferences, ensuring
customization according to their needs.
The module manages the creation process, assigns unique identifiers to new chatrooms,
and integrates features for administrators to monitor and moderate discussions effectively.
Through this module, users can foster communities, organize discussions, and engage with
peers in dynamic and purpose-driven chat environments.

3. Real Time Messaging


 The real-time messaging module enables instant communication between users within
the chatroom hub, facilitating seamless exchange of text, multimedia content, and
interactive features in real-time.
 The module supports features like message threading, notifications, and read receipts
to enhance user experience and engagement.
 It often includes robust security measures such as encryption and authentication to
safeguard messages and user privacy.
Dept of Information Technology, SVECW Page 6
CHATROOM HUB

 Real-time messaging modules are integral components of modern applications,


enabling swift and efficient communication in various contexts, from social
networking to business collaboration.

4. User Profiles

A user profiles module centralizes and manages information about individuals


within a digital system or application. It allows users to create, update, and customize their
profiles with personal details, preferences, and settings. These profiles often include user-
generated content, such as biographical information, profile pictures. The module may
offer privacy controls for users to manage the visibility of their profiles and control access
to specific information. The user profiles module serves as a cornerstone for
personalization and community building within digital platforms.

3.2 Requirement Specification

Purpose: The main purpose for preparing this document is to give a general insight into
the analysis and requirements of the existing system or situation for determining the
operational characteristics of the system.

Scope: This document plays a vital role in the software development life cycle (SDLC)
as it describes the complete requirements of the system. It is meant for use by the
developers and will be the basis for testing the system. Any changes made to the
requirements in the future will have to go through formal change approval process.

Software and Hardware Specification

 Software Requirements
 FRONT END : REACTJS
 DATABASE : FIREBASE
 IDE : VISUAL STUDIO CODE
 OPERATING SYSTEM : Windows 11

 Hardware Requirements
 8GB RAM

3.3 Technologies
3.3.1 ReactJs
React.js is an open-source JavaScript library, crafted with precision by
Facebook, that aims to simplify the intricate process of building interactive
user interfaces. Imagine a user interface built with React as a collection of
components, each responsible for outputting a small, reusable piece of
HTML code.

Dept of Information Technology, SVECW Page 7


CHATROOM HUB

In addition, React allows you to build applications using reusable components, similar to
independent Lego blocks, creating a modular and organized structure.
Its primary role is handling the view layer, encouraging developers to separate complex
UIs into reusable components for efficient rendering.

In 2011, Facebook created React to enhance user experience with dynamic and
responsive interfaces. Jordan Walke, a software engineer, simplified development by
introducing reusable components, starting with Facebook's newsfeed.

React facilitates single-page applications (SPAs) that load a single HTML document
initially and then update specific sections dynamically without reloading the entire page.
This client-side routing enhances performance and user experience.

React employs a virtual DOM, a copy of the actual DOM, to quickly reflect changes in
data states. By comparing and patching the virtual DOM to the actual DOM, React
efficiently updates components without reloading the entire page, resulting in fast and
dynamic UI changes.

Features in ReactJS

 JSX(JavaScript Syntax Extension):


 Virtual DOM
 One-way Data Binding
 Performance
 Extension
 Conditional Statements
 Components
 Simplicity
3.3.2 Firebase
Firebase Real-time database is a cloud hosted database that supports multiple
platforms Android, iOS and Web. All the data is stored in JSON format and any changes
in data, reflects immediately by performing sync across all the platforms & devices. This
allows us to build more flexible real-time apps easily with minimal effort.

Features

The main features of Firebase used in the application are:

Authentication
Firebase Authentication gives backend services, simple to-use SDKs, and instant
UI libraries to confirm clients over your application. It supports authentication using
Dept of Information Technology, SVECW Page 8
CHATROOM HUB

passwords, email id or username and with social.

You can allow users to sign in to your Firebase app either by using Firebase UI as
a complete drop-in authentication solution or by using the Firebase Authentication SDK
to manually integrate one or a few sign-in techniques into your application

Real time Database


Real-time Database is a cloud-hosted database. Data is stored as JSON and
synchronized continuously to each associated client. When you build cross-platform
applications with iOS, Android, and JavaScript SDKs, the greater part of your customers’
demand is based on one Real-time Database instance and consequently getting updates
with the most current data.
By utilizing this feature of Firebase, there is no necessity to make your own
database or own API, Firebase handles all the components that usually come along with
creating a backend for applications. It gives an adaptable, expression- based rules
language to define how your data should be organized and when information can be
perused from or composed to.

Fig 3.1

Firebase Dashboard

Dept of Information Technology, SVECW Page 9


CHATROOM HUB

Fig 3.2 Database shows the Collections created for this


application.

Fig 3.3 JSON Structure shows the fields present in the specific
key (Like Name, description...) of the collection (Rooms).

Dept of Information Technology, SVECW Page 10


CHATROOM HUB

Fig 3.4 Authentication

Fig 3.5.1. Firebase Storage represents the Firebase Storage


which has profiles folder

Dept of Information Technology, SVECW Page 11


CHATROOM HUB

Fig 3.5.2 Inside profiles folder, we store the avatars of the


users

Dept of Information Technology, SVECW Page 12


CHATROOM HUB

5. SYSTEM DESIGN

Introduction
Software design is a process of problem solving and planning for software
solutions after the purpose and specification of software are determined, software
developers will design or employ designers to develop a plan for a solution. It includes
low level component and algorithm implementation issues as well as the architectural
view.

Software Design Consideration


There are many aspects to consider in the design of software.

Compatibility
The application is compatible for any android version mobiles.

Extensibility
New capabilities can be added to the application without major changes to the
underlying architecture.

Fault-Tolerance
The application is resistant to and able to recover from failure.

Maintainability
The application can be restored to a specified condition within a specified period
of time.

Modularity:
The resulting application comprises well defined, independent modules that lead
to better maintainability.

Reliability:
The application is able to perform a required function under stated conditions for
a specified period of time.

Security:
The application is able to withstand hostile acts and influences.

Dept of Information Technology, SVECW Page 13


CHATROOM HUB

4.1 Database Design


The design starts with the end user view of the organization called conceptual
requirements and user in a decision-making, which uses information obtained by
accessing the database. The end users provide data to be stored in the database.

Table structure
We have four collections in our Realtime Database.
 Messages
 Profiles
 Rooms
 Status

Messages
 author
o avatar
o createdAt
o name
o uid
 createdAt
 likeCount
 text

Profiles
 uid
o createdAt
o email
o name

Rooms
 roomid
o admins
o createdAt
o description
o lastMessage
 author
 avatar
 createdAt
 name
 uid

Dept of Information Technology, SVECW Page 14


CHATROOM HUB

 createdAt
 file
 contentType
 name
 url
 likeCount
 msgId
 roomId
o name

Status
 roomid
o last_changed
o state

4.2 UML Diagrams


The unified Modeling Language (UML)I is a graphical language for visualizing,
specifying, constructing, and documenting the artifacts of a software intensive system.
The UML gives us a standard way to write a systems blueprint, covering conceptual
things, such as business processes and system functions, as well as classes written in a
specific programming language, database schemas, and reusable software components.

1. Use Case Diagram

Use Case diagrams are one of the five diagrams in UML for modeling the
dynamic aspects of systems. Use Case diagrams are central to modeling the behavior of a
system, a subsystem, or a class. Actors are external entities that interact with the system.
Examples of actors include users like client, administrator etc, or another system like
central database.

The step-by-step procedure that is involved in between the user and server in the below
use case diagram is:
1. Open Browser: User starts by opening a web browser.
2. Login: Then navigate to the Chatroom Hub website and enter your login credentials.
If the credentials are incorrect, you will receive an error message. Or else you will be
successfully logged into the application.
3. Profile Creation: If you’re new to Chatroom Hub, create a profile by adding a name
and avatar. You also have the option to connect your Facebook or Google accounts for
easier access and profile creation.
4. Create Chatroom: Once logged in, you can create a chatroom to start interacting with
others.
5. Send Message: Choose between sending different types of messages: text, image,

Dept of Information Technology, SVECW Page 15


CHATROOM HUB

audio, document, or video. Select the type of message and upload or type the content,
then send it into the chatroom for others to view and interact with.
6. Liking a Message: You can like messages within the chatroom as a form of
interaction or acknowledgment.
7. Get Notifications from Chatrooms: You will receive notifications about new
messages or interactions within your chatrooms.
8. Logout of Application: When you’re done, you can log out of the application
securely.

The overview of the whole project through use case diagram is as follows:

Fig 4.1 Use case Diagram for Chatroom Hub

Class Diagram

A class diagram shows a set of classes, interfaces, and collaborations and their
relationships. Class diagrams are used to illustrate the static design view of a system

Dept of Information Technology, SVECW Page 16


CHATROOM HUB

Fig 4.2 Class Diagram of Application

The Fig 4.2 shows three classes: User Account, Rooms and Messages along with their
attributes and methods that they can perform.

9. Sequence Diagram

A sequence diagram is an interaction diagram that emphasizes the time ordering


of messages. Graphically, a sequence diagram in a table that shows objects arranged
along X axis and messages, ordered in increasing time along the Y axis. It contains the
object life line that represents the existence of an object over a period of time. There is a
focus of control that shows the period of time during which an object is performing an
action, either directly or through a subordinate procedure.

The procedure that is involved in the following sequence diagram is:


The user logs into the website. The website checks the details and Firebase checks these
details against the database. If the details are valid, Firebase returns the user data to the
website, which then notifies the user of a successful login and presents the home
page.The user can edit their name and avatar.

These details are stored in the Firebase database and presented back to the user. The user
can create chat rooms. The details related to the room are stored in the Firebase database
and the chatroom is added to the website. The user can send and like messages. These
Dept of Information Technology, SVECW Page 17
CHATROOM HUB

actions are stored in the Firebase database and updated in real-time on the website. When
the user signs out, this status is updated on both the website and Firebase.
This sequence diagram provides a comprehensive guide to the user interactions with a
website and Firebase for authentication, data storage, and real-time updates.

Fig 4.3 Sequence Diagram of Application

Dept of Information Technology, SVECW Page 18


CHATROOM HUB

5. SYSTEM TESTING

5.1 Introduction
Testing is the process of detecting errors. Testing performs a very critical role for
quality assurance and for ensuring the reliability of software. The results of testing are
used later on during maintenance also.

Psychology of Testing
The aim of testing is often to demonstrate that a program works by showing that it
has no errors. The basic purpose of testing phase is to detect the errors that may be
present in the program. Hence one should not start testing with the intent of showing that
a program works, but the intent should be to show that a program doesn’t work. Testing
is the process of executing a program with the intent of finding the errors.

Testing Objectives
The main objective of testing is to uncover a host of errors, systematically and with
minimum effort and time. Stating formally, we can say,

 Testing is a process of executing a program with the intent of finding an error.


 A successful test is one that uncovers an as yet undiscovered error.
 A good test case is one that has a high probability of finding error, if it exists.
 The tests are inadequate to detect possibly present errors.
 The software more or less confirms to the quality and reliable standards.

5.2 Types of Testing


 Unit Testing
 Link Testing
 System Testing
 Acceptance Testing

Unit Testing
Unit testing focuses verification effort on the smallest unit of software i.e. the
module. Using the detailed design and the process specifications testing is done to
uncover errors within the boundary of the module. All modules must be successful in the
unit test before the start of the integration testing begins.

Dept of Information Technology, SVECW Page 19


CHATROOM HUB

Link Testing
Link testing does not test software but rather the integration of each module in
system. The primary concern is the compatibility of each module. The programmer tests
where modules are designed with different parameters, length, type etc.

Integration Testing
After the unit testing we have to perform integration testing. The goal here is to
see if modules can be integrated properly, the emphasis being on testing interfaces
between modules. This testing activity can be considered as testing the design and hence
the emphasis on testing module interactions.

System Testing
Here the entire software system is tested. The reference document for this process
is the requirements document, and the goal is to see if software meets its requirements.
Here entire project has been tested against requirements of project and it is checked
whether all requirements of project have been satisfied or not.

Acceptance Testing
Acceptance Test is performed with realistic data of the client to demonstrate that
the software is working satisfactorily. Testing here is focused on external behavior of the
system; the internal logic of program is not emphasized.

Dept of Information Technology, SVECW Page 20


OUTING MANAGEMENT

5.3 Test Cases

S.No Input Actual Output Expected Output


1 Authorized User Login User successfully logs in User successfully logs in
2 Unauthorized User Login User is not granted access. User is not granted access.
3 Chatroom creation with unique Chatroom is successfully created Chatroom is successfully
name and listed in the chatroom hub. created and listed in the
chatroom hub.

4 Chatroom creation with existing Chatroom is not created and gets a Chatroom is not created and
name popup “Already exists” gets a popup “Already exists”
5 Edit the Username Username set successfully. Username set successfully.
6 Upload the new Avatar Avatar has been uploaded Avatar has been uploaded
7 User sends the Text Message Message is displayed in the Message is displayed in the
chatroom for all users to see. chatroom for all users to see.
8 User sends the Documents Documents are displayed in the Documents are displayed in the
chatroom for all users to see. chatroom for all users to see.
9 User sends the Pictures Pictures are displayed in the Pictures are displayed in the
chatroom for all users to see. chatroom for all users to see.
10 User sends the Voice Message Message is displayed in the Message is displayed in the
chatroom for all users to see. chatroom for all users to see.
11 User likes the Message Heart emoji is attached to the Heart emoji is attached to the
message. message.
12 User Logout Successfully logged out Successfully logged out

Table 5.3.1 Test Cases for chatroom application

Dept of Information Technology, SVECW Page 21


OUTING MANAGEMENT

6. LAYOUT DESIGNS

Welcome page: It is the first Web Interface that appears when we enter into the Chatroom Hub
application. This page consists of Login/Signup options through Facebook, Google and Email.

Fig 6.1 User Login/Signup through


different social media platforms.

Google Sign up page: When the user chooses to login through google, it provide his/her
Google accounts details like below.

Fig 6.2 Displaying Google accounts


history

Dept of Information Technology, SVECW Page 22


OUTING MANAGEMENT

Login Page: The user logs into the application by providing registered Email and password.

Fig 6.3 Login Page for users

Successful Sign-up alert:

Fig 6.4 Starting page inside of chatroom hub with successful sign-in alert

Dept of Information Technology, SVECW Page 23


OUTING MANAGEMENT

Fig 6.5 User’s Dashboard with their name associated with their respective account

Updating Username: The user has an option to change their name by their choice from the
name that is associated with their account. It gives success alert after updating it.

Fig 6.6 Showing Success alert after updating their username in the dash board

Dept of Information Technology, SVECW Page 24


OUTING MANAGEMENT

Uploading new avatar: When user clicks on the icon with their starting initials of their
name which is a default feature if we didn’t add a avatar, it displays a window to choose an
image of formats (jpg, jpeg, png) and after fixing the image, the page appears as below figure.

Fig 6.7 Updating new avatar

Displaying updated avatar: On clicking the UPLOAD NEW AVATAR button, the new
avatar of user’s choice will be updated on their dashboard and gives a successful alert for it.

Fig 6.8 Displaying new avatar on the dashboard

Dept of Information Technology, SVECW Page 25


OUTING MANAGEMENT

 Changing Nickname: On clicking the input text box and updating the nickname
will change the nickname in the user dashboard.

Fig 6.9 Changing Nickname

 Displaying created chatrooms and chats: The below figure shows a web
interface which shows different chatrooms created by different people and chats available
in each chatroom.

Fig 6.10 Displaying chats available in different chatrooms like Fitness Fusion,
Wanderlust Explorers...etc.
Dept of Information Technology, SVECW Page 26
OUTING MANAGEMENT

 Liking a message: The below figure shows a message sent by Geethika was liked by
some other user in Wanderlust Explorers chatroom.

Fig 6.11 Liking a message in a chatroom

 Deleting a message: The user can delete their own message that is sent in a chatroom
but doesn’t have access to delete messages sent by others.

Fig 6.12 Deleting a message in chats

Dept of Information Technology, SVECW Page 27


OUTING MANAGEMENT

Editing room details: Every chatroom has a admin who created it and will have access to
change name and description of the chatroom which was shown in the below figure.

Fig 6.13 Editing Room details

Fig 6.14 Showing Updated Room details

Dept of Information Technology, SVECW Page 28


OUTING MANAGEMENT

Shows User profile: Every admin has access to give admin permissions to other members in
the chatroom which is shown in the below figure.

Fig 6.15 Making other members as admin

Uploading files: By clicking ‘PIN’ symbol button, we will get a dialog box as shown in the
below figure.

Fig 6.16 Shows dialog box while


uploading files

Dept of Information Technology, SVECW Page 29


OUTING MANAGEMENT

Fig 6.17 Selecting and Uploading files

After Uploading files: The file will be uploaded and displayed in the chatroom as below.

Fig 6.18 Final view of chatroom after


uploading file

Dept of Information Technology, SVECW Page 30


OUTING MANAGEMENT

7. CONCLUSION AND FUTURE WORK

The Chatroom Hub project successfully achieved its objectives by providing a


comprehensive and interactive platform for users to engage in real-time communication. The
implementation of functionalities like admin control in chatrooms, avatar customization,
message liking and deletion, and ensuring a responsive application showcase the versatility of
the system.

The platform offers a wide array of communication tools, promoting efficient and
engaging discussions among users. The application's responsiveness across various devices
enhances accessibility, ensuring a seamless user experience. Users can tailor chatrooms to their
specific interests and needs, creating a personalized environment. Document sharing and real-
time editing capabilities facilitate collaborative projects and discussions. The Seamlessly
integrate multimedia content into conversations, making communication more dynamic and
expressive.

The project not only meets the technical requirements but also focuses on user experience
and interactivity. The incorporation of admin controls adds an additional layer of customization
and security to the chatrooms. Overall, Chatroom Hub successfully leverages cutting-edge
technologies to create a feature-rich and user-friendly communication platform.

It is not possible to develop a system that makes all the requirements of the user. User
requirements keep changing as the system is being used. Some of the future enhancements that
can be done to the system are:

 As the technology emerges, it is possible to upgrade the system and can be adaptable to
desired environment.
 We can allow users to customize the look and feel of their chatrooms by providing various
themes and color schemes.
 We can develop an offline mode that allows users to access and interact with previously
loaded content, even without an active internet connection.
 We can strengthen security measures by implementing end-to-end encryption for messages,
ensuring a higher level of privacy for users.
 We can enhance accessibility features to ensure the application is usable by individuals with
disabilities, adhering to accessibility standards and guidelines.

These future enhancements aim to elevate the Chatroom Hub project by expanding its features,
improving user engagement, and adapting to emerging trends in communication and technology.

Dept of Information Technology, SVECW Page 31


OUTING MANAGEMENT

8. REFERENCES

⚫ https://en.wikipedia.org/wiki/Firebase

⚫ https://react.dev/

⚫ https://legacy.reactjs.org/docs/handling-events.html

⚫ https://firebase.google.com/

⚫ https://youtu.be/8QgQKRcAUvM?si=swrk9sZXvWMHTxM7

⚫ https://youtu.be/ad6IavyAHsQ?si=x1tXd8-SAsMcGMxD

Dept of Information Technology, SVECW Page 32


OUTING MANAGEMENT

9. APPENDIX

SAMPLE CODE :

src

components

chat-window

bottom

AttachmentBtn.js:

import React,{useCallback, useEffect, useRef, useState} from 'react';


import {Button} from 'rsuite';
import {useParams} from 'react-router-dom';
import {auth,database, storage} from '../../../misc/firebase';
import {ref,orderByChild,query,equalTo,onValue,off,runTransaction,update,limitToLast} from
"firebase/database";
import {ref as storageRef,deleteObject} from "firebase/storage";
import {transformToArrWithId} from '../../../misc/helper';
import MessageItem from './MessageItem';
import { ToastContainer, toast } from 'react-toastify';
import {groupBy} from '../../../misc/helper'

const pageSize = 15;


const messagesRef = ref(database,'/messages');
function shouldScrollToBottom(node,threshold = 30){
const percentage = (100*node.scrollTop) / (node.scrollHeight - node.clientHeight) || 0;
return percentage > threshold;
}
const Messages = () => {
const {chatId} = useParams();
const [messages,setMessages] = useState(null);
const [limit,setLimit] = useState(pageSize);
const selfRef = useRef();

const isChatEmpty = messages && messages.length === 0;


const canShowMessages = messages && messages.length > 0;
const loadMessages = useCallback((limit)=>{
const node = selfRef.current;
off(messagesRef);

Dept of Information Technology, SVECW Page 33


OUTING MANAGEMENT

const queryGet = query(messagesRef, orderByChild('roomId'),


equalTo(chatId),limitToLast(limit || pageSize));
console.log("query"+" "+queryGet);
onValue(queryGet, (snapshot) => {
console.log("inside messages yay");
const data = transformToArrWithId(snapshot.val());
setMessages(data);
if(shouldScrollToBottom(node)){
node.scrollTop = node.scrollHeight;
}
});
setLimit(p => p + pageSize);
},[chatId]);

const onLoadMore = useCallback(()=>{


const node = selfRef.current;
const oldHeight = node.scrollHeight;
loadMessages(limit);
setTimeout(()=>{
const newHeight = node.scrollHeight;
node.scrollTop = newHeight - oldHeight;
})
},[loadMessages,limit]);

useEffect(()=>{
const node = selfRef.current;
loadMessages();
setTimeout(()=>{
node.scrollTop = node.scrollHeight;
},200);
return ()=>{
off(messagesRef,'value');
}
},[loadMessages]);

const handleAdmin = useCallback(async(uid)=>{


const adminsRef = ref(database,`/rooms/${chatId}/admins`);
let alertMsg;
await runTransaction(adminsRef, (admins) => {
if (admins) {
if (admins[uid]) {
admins[uid] = null;
alertMsg = 'Admin permission removed';
} else {
admins[uid] = true;
alertMsg = 'Admin permission granted';
Dept of Information Technology, SVECW Page 34
OUTING MANAGEMENT

}
}
return admins;
});
toast.info(alertMsg, {
position: toast.POSITION.TOP_CENTER, // Align to the center
autoClose: 4000, // Auto-close the alert after 5000 milliseconds (5 seconds)
});
},[chatId])

const handleLike = useCallback(async(msgId)=>{


const {uid} = auth.currentUser;
const msgRef = ref(database,`/messages/${msgId}`);
let alertMsg;
await runTransaction(msgRef, (msg) => {
if (msg) {
if (msg.likes && msg.likes[uid]) {
msg.likeCount -= 1;
msg.likes[uid] = null;
alertMsg = 'Like removed';
} else {
msg.likeCount += 1;
if(!msg.likes){
msg.likes = {};
}
msg.likes[uid] = true;
alertMsg = 'Like added';
}
}
return msg;
});
toast.info(alertMsg, {
position: toast.POSITION.TOP_CENTER, // Align to the center
autoClose: 4000, // Auto-close the alert after 5000 milliseconds (5 seconds)
});
},[]);

const handleDelete = useCallback(async(msgId,file)=>{


if(!window.confirm('Delete this message?')){
return;
}
const isLast = messages[messages.length - 1].id == msgId;
const updates = {};
updates[`/messages/${msgId}`] = null;
if(isLast && messages.length > 1){
updates[`/rooms/${chatId}/lastMessage`] = {
Dept of Information Technology, SVECW Page 35
OUTING MANAGEMENT

...messages[messages.length - 2],
msgId : messages[messages.length - 2].id
}
}
if(isLast && messages.length === 1){
updates[`/rooms/${chatId}/lastMessage`] = null;
}
try{
await update(ref(database),updates);
toast.info('Message has been deleted', {
position: toast.POSITION.TOP_CENTER, // Align to the center
autoClose: 4000, // Auto-close the alert after 5000 milliseconds (5 seconds)
});
}catch(err){
return toast.error(err.message, {
position: toast.POSITION.TOP_CENTER, // Align to the center
autoClose: 4000, // Auto-close the alert after 5000 milliseconds (5 seconds)
});
}
if(file){
try{
const fileRef = await storageRef(storage,file.url);
await deleteObject(fileRef);
}catch(err){
toast.error(err.message, {
position: toast.POSITION.TOP_CENTER, // Align to the center
autoClose: 4000, // Auto-close the alert after 5000 milliseconds (5 seconds)
});
}
}
},[chatId,messages])

const renderMessages = () => {


const groups = groupBy(messages,(item) => new Date(item.createdAt).toDateString());
const items = [];
Object.keys(groups).forEach((date)=>{
items.push(<li key={date} className='text-center mb-1 padded'>{date}</li>)
const msgs = groups[date].map(msg=>(
<MessageItem key = {msg.id} message = {msg} handleAdmin={handleAdmin}
handleLike={handleLike} handleDelete={handleDelete}/>
))
items.push(...msgs);
})
return items;
}
return (
Dept of Information Technology, SVECW Page 36
OUTING MANAGEMENT

<ul ref={selfRef} className='msg-list custom-scroll'>


{messages && messages.length >= pageSize && (
<li className='text-center mt-2 mb-2'>
<Button onClick={onLoadMore} color='green' appearance='primary'>Load more</Button>
</li>
)}
{isChatEmpty && <li>No messages yet...</li>}
{canShowMessages && renderMessages()}
</ul>
)
}

export default Messages;

AudioMsgBtn.js :

import React, { useCallback, useState } from 'react';


import { InputGroup } from 'rsuite';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faMicrophone } from '@fortawesome/free-solid-svg-icons';
import { ReactMic } from 'react-mic';
import {storage} from '../../../misc/firebase';
import {ref,uploadBytes,getDownloadURL} from 'firebase/storage'
import { useParams } from 'react-router';
import { ToastContainer, toast } from 'react-toastify';

const AudioMsgBtn = ({afterUpload}) => {


const {chatId} = useParams();
const [isRecording,setIsRecording] = useState(false);
const [isUploading,setIsUploading] = useState(false);
const onUpload = useCallback(async(data)=>{
setIsUploading(true);
try{
const storageRef = ref(storage, `chatId/${chatId}/audio_${Date.now()}.mp3`);
const metadata = {
cacheControl: `public,max-age=${3600*24*3}`,
};

const snap = await uploadBytes(storageRef, data.blob, metadata);


const file = {
contentType : snap.metadata.contentType,
name : snap.metadata.name,
url : await getDownloadURL(snap.ref),
}
Dept of Information Technology, SVECW Page 37
OUTING MANAGEMENT

setIsUploading(false);
afterUpload([file]);
}catch(err){
setIsUploading(false);
toast.error(err.message, {
position: toast.POSITION.TOP_CENTER, // Align to the center
autoClose: 4000, // Auto-close the alert after 5000 milliseconds (5 seconds)
});
}
},[afterUpload,chatId])
const onClick = useCallback(()=>{
setIsRecording(p => !p);
},[]);
return (
<InputGroup.Button onClick={onClick} disabled = {isUploading} className={isRecording ?
'animate-blink' : ''}>
<FontAwesomeIcon icon={faMicrophone} />
<ReactMic
record = {isRecording}
className = "d-none"
onStop = {onUpload}
mimeType = "audio/mp3"
/>
</InputGroup.Button>
)
}

export default AudioMsgBtn;

index.js :

import React,{useCallback, useState,useContext} from 'react';


import { InputGroup, Input } from 'rsuite';
import SendIcon from '@rsuite/icons/Send';
import '../../../styles/main.scss';
import { ref,serverTimestamp,push,update } from 'firebase/database';
import { ProContext } from '../../../context/ProfileContext';
import {useParams} from 'react-router-dom';
import {database} from '../../../misc/firebase';
import { ToastContainer, toast } from 'react-toastify';
import AttachmentBtnModal from './AttachmentBtnModal';
import AudioMsgBtn from './AudioMsgBtn';

function assembleMessage(profile,chatId){
return{
Dept of Information Technology, SVECW Page 38
OUTING MANAGEMENT

roomId : chatId,
author : {
name : profile.name,
uid : profile.uid,
createdAt : profile.createdAt,
...(profile.avatar ? {avatar : profile.avatar} : {})
},
createdAt : serverTimestamp(),
likeCount : 0
}
}

const Bottom = () => {


const [input,setInput] = useState('');
const [isLoading,setIsLoading] = useState(false);

const {chatId} = useParams();


const {profile} = useContext(ProContext);

const onInputChange = useCallback((value)=>{


setInput(value);
},[]);

const onSendClick = async() => {


if(input.trim() === ""){
return;
}
const msgData = assembleMessage(profile,chatId);
console.log(msgData);
msgData.text = input;

const updates = {};


const messageId = push(ref(database, 'messages'));
const newMessageKey = messageId.key;
console.log(newMessageKey);
updates[`/messages/${newMessageKey}`] = msgData;
updates[`/rooms/${chatId}/lastMessage`] = {
...msgData,
msgId : newMessageKey,
};
setIsLoading(true);
try{
await update(ref(database), updates);
setInput('');
setIsLoading(false);
}catch(err){
Dept of Information Technology, SVECW Page 39
OUTING MANAGEMENT

setIsLoading(false);
toast.error(err.message, {
position: toast.POSITION.TOP_CENTER,
autoClose: 2000,
});
}

const onKeyDown = (ev) => {


console.log(ev);
console.log(ev.keyCode);
if(ev.keyCode === 13){
ev.preventDefault();
onSendClick();
}
}

const afterUpload = useCallback(async(files)=>{


setIsLoading(true);
const updates = {};
files.forEach(file=>{
const msgData = assembleMessage(profile,chatId);
msgData.file = file;
const messageId = push(ref(database, 'messages'));
const newMessageKey = messageId.key;
updates[`/messages/${newMessageKey}`] = msgData;

})
const lastMsgId = Object.keys(updates).pop();
updates[`/rooms/${chatId}/lastMessage`] = {
...updates[lastMsgId],
msgId : lastMsgId,
};
try{
await update(ref(database), updates);
setIsLoading(false);
}catch(err){
setIsLoading(false);
toast.error(err.message, {
position: toast.POSITION.TOP_CENTER,
autoClose: 2000,
});
}
},[chatId,profile])

Dept of Information Technology, SVECW Page 40


OUTING MANAGEMENT

return (
<div>
<InputGroup style={{width : "66%"}}>
<AttachmentBtnModal afterUpload={afterUpload}/>
<AudioMsgBtn afterUpload={afterUpload}/>
<Input name='chat' placeholder='Write new messages here.....' value = {input}
onChange={onInputChange} onKeyDown={onKeyDown} style={{width:"66%",color: 'black',
fontWeight: 'bolder' }}/>
<InputGroup.Button title="Send Message" color='blue' appearance='primary'
onClick={onSendClick} disabled={isLoading}>
<SendIcon />
</InputGroup.Button>
</InputGroup>
<ToastContainer />
</div>
);
};

export default Bottom;

messages

IconBtnControl.js :

import React from 'react';


import {Badge,Tooltip,Whisper,IconButton} from 'rsuite';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faHeart} from '@fortawesome/free-solid-svg-icons';
import CloseIcon from '@rsuite/icons/Close';

const ConditionalBadge = ({condition,children}) => {


return condition ? <Badge content = {condition}>{children}</Badge> : children;
}
const IconBtnControl = ({isVisible,iconName,tooltip,onClick,badgeContent,...props}) => {
return (
<div className='ml-2' style={{visibility : isVisible ? 'visible' : 'hidden'}}>
<ConditionalBadge condition={badgeContent}>
<Whisper placement='top' delay={0} delayClose={0} delayOpen={0} trigger="hover"
speaker={<Tooltip>{tooltip}</Tooltip>}>
<IconButton {...props} onClick={onClick} circle size='xs' icon={iconName ==
"heart" ? <FontAwesomeIcon icon={faHeart} /> : <CloseIcon/>}/>
</Whisper>
</ConditionalBadge>
</div>
)

Dept of Information Technology, SVECW Page 41


OUTING MANAGEMENT

export default IconBtnControl;

ImgBtnModal.js :

import React from 'react'


import { useModelState } from '../../../misc/custom-hooks'
import { Modal,Input } from 'rsuite';

const ImgBtnModal = ({src,fileName}) => {


const {isOpen,open,close} = useModelState();
return (
<>
<input type = "image" src = {src} alt = "file" onClick = {open} loading = "lazy"
className="mw-100 mh-100 w-auto img-b "/>
<Modal open = {isOpen} onClose = {close}>
<Modal.Header>
<Modal.Title>{fileName}</Modal.Title>
</Modal.Header>
<Modal.Body>
<div>
<img src = {src} height = "100%" width = "100%" alt = "file" className = "mt-3" />
</div>
</Modal.Body>
<Modal.Footer>
<a href = {src} target = "_blank" rel = "noopener noreferrer" >
View original
</a>
</Modal.Footer>
</Modal>
</>
)
}

export default ImgBtnModal;

index.js :

import React,{useCallback, useEffect, useRef, useState} from 'react';


import {Button} from 'rsuite';
import {useParams} from 'react-router-dom';
import {auth,database, storage} from '../../../misc/firebase';
import {ref,orderByChild,query,equalTo,onValue,off,runTransaction,update,limitToLast} from
"firebase/database";
Dept of Information Technology, SVECW Page 42
OUTING MANAGEMENT

import {ref as storageRef,deleteObject} from "firebase/storage";


import {transformToArrWithId} from '../../../misc/helper';
import MessageItem from './MessageItem';
import { ToastContainer, toast } from 'react-toastify';
import {groupBy} from '../../../misc/helper'

const pageSize = 15;


const messagesRef = ref(database,'/messages');
function shouldScrollToBottom(node,threshold = 30){
const percentage = (100*node.scrollTop) / (node.scrollHeight - node.clientHeight) || 0;
return percentage > threshold;
}
const Messages = () => {
const {chatId} = useParams();
const [messages,setMessages] = useState(null);
const [limit,setLimit] = useState(pageSize);
const selfRef = useRef();

const isChatEmpty = messages && messages.length === 0;


const canShowMessages = messages && messages.length > 0;
const loadMessages = useCallback((limit)=>{
const node = selfRef.current;
off(messagesRef);
const queryGet = query(messagesRef, orderByChild('roomId'),
equalTo(chatId),limitToLast(limit || pageSize));
console.log("query"+" "+queryGet);
onValue(queryGet, (snapshot) => {
console.log("inside messages yay");
const data = transformToArrWithId(snapshot.val());
setMessages(data);
if(shouldScrollToBottom(node)){
node.scrollTop = node.scrollHeight;
}
});
setLimit(p => p + pageSize);
},[chatId]);

const onLoadMore = useCallback(()=>{


const node = selfRef.current;
const oldHeight = node.scrollHeight;
loadMessages(limit);
setTimeout(()=>{
const newHeight = node.scrollHeight;
node.scrollTop = newHeight - oldHeight;
})
Dept of Information Technology, SVECW Page 43
OUTING MANAGEMENT

},[loadMessages,limit]);

useEffect(()=>{
const node = selfRef.current;
loadMessages();
setTimeout(()=>{
node.scrollTop = node.scrollHeight;
},200);
return ()=>{
off(messagesRef,'value');
}
},[loadMessages]);

const handleAdmin = useCallback(async(uid)=>{


const adminsRef = ref(database,`/rooms/${chatId}/admins`);
let alertMsg;
await runTransaction(adminsRef, (admins) => {
if (admins) {
if (admins[uid]) {
admins[uid] = null;
alertMsg = 'Admin permission removed';
} else {
admins[uid] = true;
alertMsg = 'Admin permission granted';
}
}
return admins;
});
toast.info(alertMsg, {
position: toast.POSITION.TOP_CENTER, // Align to the center
autoClose: 4000, // Auto-close the alert after 5000 milliseconds (5 seconds)
});
},[chatId])

const handleLike = useCallback(async(msgId)=>{


const {uid} = auth.currentUser;
const msgRef = ref(database,`/messages/${msgId}`);
let alertMsg;
await runTransaction(msgRef, (msg) => {
if (msg) {
if (msg.likes && msg.likes[uid]) {
msg.likeCount -= 1;
msg.likes[uid] = null;
alertMsg = 'Like removed';
} else {
msg.likeCount += 1;
Dept of Information Technology, SVECW Page 44
OUTING MANAGEMENT

if(!msg.likes){
msg.likes = {};
}
msg.likes[uid] = true;
alertMsg = 'Like added';
}
}
return msg;
});
toast.info(alertMsg, {
position: toast.POSITION.TOP_CENTER, // Align to the center
autoClose: 4000, // Auto-close the alert after 5000 milliseconds (5 seconds)
});
},[]);

const handleDelete = useCallback(async(msgId,file)=>{


if(!window.confirm('Delete this message?')){
return;
}
const isLast = messages[messages.length - 1].id == msgId;
const updates = {};
updates[`/messages/${msgId}`] = null;
if(isLast && messages.length > 1){
updates[`/rooms/${chatId}/lastMessage`] = {
...messages[messages.length - 2],
msgId : messages[messages.length - 2].id
}
}
if(isLast && messages.length === 1){
updates[`/rooms/${chatId}/lastMessage`] = null;
}
try{
await update(ref(database),updates);
toast.info('Message has been deleted', {
position: toast.POSITION.TOP_CENTER, // Align to the center
autoClose: 4000, // Auto-close the alert after 5000 milliseconds (5 seconds)
});
}catch(err){
return toast.error(err.message, {
position: toast.POSITION.TOP_CENTER, // Align to the center
autoClose: 4000, // Auto-close the alert after 5000 milliseconds (5 seconds)
});
}
if(file){
try{
const fileRef = await storageRef(storage,file.url);
Dept of Information Technology, SVECW Page 45
OUTING MANAGEMENT

await deleteObject(fileRef);
}catch(err){
toast.error(err.message, {
position: toast.POSITION.TOP_CENTER, // Align to the center
autoClose: 4000, // Auto-close the alert after 5000 milliseconds (5 seconds)
});
}
}
},[chatId,messages])

const renderMessages = () => {


const groups = groupBy(messages,(item) => new Date(item.createdAt).toDateString());
const items = [];
Object.keys(groups).forEach((date)=>{
items.push(<li key={date} className='text-center mb-1 padded'>{date}</li>)
const msgs = groups[date].map(msg=>(
<MessageItem key = {msg.id} message = {msg} handleAdmin={handleAdmin}
handleLike={handleLike} handleDelete={handleDelete}/>
))
items.push(...msgs);
})
return items;
}
return (
<ul ref={selfRef} className='msg-list custom-scroll'>
{messages && messages.length >= pageSize && (
<li className='text-center mt-2 mb-2'>
<Button onClick={onLoadMore} color='green' appearance='primary'>Load more</Button>
</li>
)}
{isChatEmpty && <li>No messages yet...</li>}
{canShowMessages && renderMessages()}
</ul>
)
}

export default Messages;

MessageItem.js

import React,{memo} from 'react'


import ProfileAvatar from '../../ProfileAvatar';
import TimeAgo from 'timeago-react';
import ProfileInfoBtn from './ProfileInfoBtn';
import '../../../styles/main.scss';
Dept of Information Technology, SVECW Page 46
OUTING MANAGEMENT

import PresenceDot from '../../PresenceDot';


import { Button } from 'rsuite';
import {useCurrentRoom} from "../../../context/current-room.context";
import {auth} from "../../../misc/firebase";
import IconBtnControl from './IconBtnControl';
import {useHover} from '../../../misc/custom-hooks';
import ImgBtnModal from './ImgBtnModal';

const renderFileMessage = (file) => {


if (file.contentType.includes('image')) {
return (
<div className="height-220 mt-2">
<ImgBtnModal src={file.url} fileName={file.name} />
</div>
);
}
if(file.contentType.includes('audio')){
return (
<audio controls>
<source src={file.url} type='audio/mp3'/>
Your browser does not support the audio element...
</audio>
);
}
return <a href={file.url}>Download {file.name}</a>
}

const MessageItem = ({message,handleAdmin,handleLike,handleDelete}) => {


const {author,createdAt,text,file,likes,likeCount} = message;
const [selfRef, isHovered] = useHover();
const isMobile = window.innerWidth <= 767;
const isAdmin = useCurrentRoom(v=>v.isAdmin);
const admins = useCurrentRoom(v=>v.admins);
const isMsgAuthorAdmin = admins.includes(author.uid);
const isAuthor = auth.currentUser.uid === author.uid;
const canGrantAdmin = isAdmin && !isAuthor;
const canShowIcons = isMobile || isHovered;
const isLiked = likes && Object.keys(likes).includes(auth.currentUser.uid);

return (
<li className={`padded mb-1 cursor-pointer ${isHovered ? 'bg-black-02' : ''}`}
ref={selfRef}>
<div className='d-flex align-items-center font-bolder mb-1'>
<PresenceDot uid = {author.uid}/>
Dept of Information Technology, SVECW Page 47
OUTING MANAGEMENT

<ProfileAvatar src = {author.avatar} name = {author.name} className = "ml-1" size =


"xs"/>
<ProfileInfoBtn profile = {author} appearance = "link" className = "p-0 ml-1 text-black">
{canGrantAdmin &&
<Button block color="blue" appearance="primary"
onClick={()=>handleAdmin(author.uid)} >
{isMsgAuthorAdmin ? 'Remove admin permission':'Give admin permission to this
room'}
</Button>}
</ProfileInfoBtn>
<TimeAgo
datetime={createdAt}
className="font-normal text-black-45 ml-2"/>
<IconBtnControl {...(isLiked ? {color : 'red',appearance:'primary'} : {})} isVisible =
{canShowIcons} iconName = "heart" tooltip = "Like this message" onClick =
{()=>{handleLike(message.id)}} badgeContent={likeCount}/>
{
isAuthor && (
<IconBtnControl isVisible = {canShowIcons} iconName = "close" tooltip = "Delete this
message" onClick = {()=>{handleDelete(message.id,file)}} />
)
}
</div>
<div>
{
text && <span className='word-break-all'>{text}</span>
}
{
file && renderFileMessage(file)
}

</div>
</li>
)
}

export default memo(MessageItem);

ProfileInfoBtn.js :

import React from 'react';


import {Button,Modal} from 'rsuite';
import { useModelState } from '../../../misc/custom-hooks';
import ProfileAvatar from '../../ProfileAvatar';

Dept of Information Technology, SVECW Page 48


OUTING MANAGEMENT

const ProfileInfoBtn = ({profile,children,...btnProps}) => {


const {isOpen,close,open} = useModelState();
const shortName = profile.name.split(' ')[0];
const {name,avatar,createdAt} = profile;
const memberSince = new Date(createdAt).toLocaleDateString();

return (
<>
<Button {...btnProps} onClick={open} >
{shortName}
</Button>
<Modal open = {isOpen} onClose = {close}>
<Modal.Header>
<Modal.Title>{shortName} profile</Modal.Title>
</Modal.Header>
<Modal.Body className='text-center'>
<ProfileAvatar src = {avatar} name = {name} className = "width-200 height-200 img-
fullsize font-huge"/>
<h4 className='mt-2'>{name}</h4>
<p>Member since {memberSince}</p>
</Modal.Body>
<Modal.Footer>
{children}
<Button block onClick={close}>Close</Button>
</Modal.Footer>
</Modal>
</>
)
}

export default ProfileInfoBtn

top

EditRoomBtnDrawer.js :

import React,{memo} from 'react';


import {useParams} from 'react-router-dom';
import {Button,Drawer} from 'rsuite';
import { useModelState } from '../../../misc/custom-hooks';
import EditableInput from '../../EditableInput';
import { useCurrentRoom } from '../../../context/current-room.context';
import {database} from '../../../misc/firebase';
import {ref,set} from "firebase/database";

Dept of Information Technology, SVECW Page 49


OUTING MANAGEMENT

import { ToastContainer, toast } from 'react-toastify';

const EditRoomBtnDrawer = () => {


const {isOpen,open,close} = useModelState();
const {chatId} = useParams();
const name = useCurrentRoom(v => v.name);
const description = useCurrentRoom(v => v.description);
const updateData = (key,value) => {
const chatRef = ref(database, `rooms/${chatId}/${key}`);
set(chatRef, value).then(() => {
toast.success("Successfully Updated", {
position: toast.POSITION.TOP_CENTER,
autoClose: 4000,
});
}).catch((error) => {
toast.error(`Error${error.message}`, {
position: toast.POSITION.TOP_CENTER,
autoClose: 4000,
});
});
}
const onNameSave = (newName) => {
updateData('name',newName);
}
const onDescriptionSave = (newDesc) => {
updateData('description',newDesc);
}
return (
<div>
<Button className='br-circle' size='sm' color='red' appearance='primary' onClick={open}>
A
</Button>
<Drawer open = {isOpen} onClose = {close} placement='right'>
<Drawer.Header>
<Drawer.Title>
Edit Room
</Drawer.Title>
</Drawer.Header>
<Drawer.Body style={{margin:0,padding: 0,marginTop:5}}>
<EditableInput initialValue = {name} onSave={onNameSave} label={<h6
className='mb-2'>Name</h6>} emptyMsg='Name cannot be empty'/>
<EditableInput as = "textarea" rows = {5} initialValue = {description} onSave =
{onDescriptionSave} emptyMsg='Description cannot be empty' wrapperClassName='mt-3'/>
<Button block style={{ position: 'absolute', bottom: '0'}} onClick = {close}>
Close
</Button>
Dept of Information Technology, SVECW Page 50
OUTING MANAGEMENT

</Drawer.Body>
</Drawer>
<ToastContainer/>
</div>
)
}

export default memo(EditRoomBtnDrawer);

index.js :

import React,{memo} from 'react'


import { useCurrentRoom } from '../../../context/current-room.context'
import ArrowLeftIcon from '@rsuite/icons/ArrowLeft';
import { Link } from 'react-router-dom';
import { ButtonToolbar } from 'rsuite';
import '../../../styles/main.scss';
import RoomInfoBtnModel from './RoomInfoBtnModel';
import EditRoomBtnDrawer from './EditRoomBtnDrawer';

const Top = () => {


const name = useCurrentRoom(v => v.name);
const isAdmin = useCurrentRoom(v => v.isAdmin);
const isMobile = window.innerWidth <= 767
return (
<div>
<div className='d-flex justify-content-between align-items-center'>
<h4 className='text-disappear d-flex align-items-center'>
<Link to="/" className={isMobile ? 'd-inline-block p-0 mr-2 text-blue link-unstyled':'d-
none'}><ArrowLeftIcon color='blue'/></Link>
<span className='text-disappear'>{name}</span>
</h4>
<ButtonToolbar >
{
isAdmin && <EditRoomBtnDrawer/>
}
</ButtonToolbar>
</div>
<div className='d-flex justify-content-between align-items-center'>
<span>todo</span>
<RoomInfoBtnModel/>
</div>
</div>
)
}

Dept of Information Technology, SVECW Page 51


OUTING MANAGEMENT

export default memo(Top);

RoomInfoBtnModel.js :

import React,{memo} from 'react';


import {Button,Modal} from 'rsuite';
import { useCurrentRoom } from '../../../context/current-room.context';
import { useModelState } from '../../../misc/custom-hooks';

const RoomInfoBtnModel = () => {


const {isOpen,close,open} = useModelState();
const description = useCurrentRoom(v=>v.description);
const name = useCurrentRoom(v=>v.name);
return (
<>
<Button appearance='link' className='px-0' onClick={open}>
Room information
</Button>
<Modal open = {isOpen} onClose = {close}>
<Modal.Header>
<Modal.Title>
About {name}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<h6 className='mb-1'>Description</h6>
<p>{description}</p>
</Modal.Body>
<Modal.Footer>
<Button block onClick = {close}>
Close
</Button>
</Modal.Footer>
</Modal>
</>
)
}

export default memo(RoomInfoBtnModel);

Dept of Information Technology, SVECW Page 52


OUTING MANAGEMENT

dashboard

AvatarUploadBtn.js:

import React,{useState,useRef,useContext} from 'react'


import '../../styles/main.scss';
import {Modal,Button} from 'rsuite';
import {useModelState} from '../../misc/custom-hooks';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import AvatarEditor from 'react-avatar-editor';
import {storage,database} from '../../misc/firebase';
import {ref as databaseRef,set,update} from 'firebase/database';
import {ref as storageRef,uploadBytes,getDownloadURL} from 'firebase/storage';
import { ProContext } from '../../context/ProfileContext';
import ProfileAvatar from '../ProfileAvatar';
import '../../styles/main.scss';
import '../../styles/utility.scss';
import {getUserUpdate} from '../../misc/helper';

const fileInputTypes = ".png, .jpeg, .jpg";


const acceptedFileTypes = ['image/png','image/jpeg','image/pjpeg','image/jpg']
const isValidFile = (file) => acceptedFileTypes.includes(file.type);
const getBlob = (canvas) => {
return new Promise((resolve,reject)=>{
canvas.toBlob((blob)=>{
if(blob){
resolve(blob);
}
else{
reject(new Error('File process error'));
}
})
})
}
const AvatarUploadBtn = () => {
const {isOpen,open,close} = useModelState();
const [image,setImage] = useState(null);
const avatarEditorRef = useRef();
const {profile} = useContext(ProContext);
const [isLoading,setIsLoading] = useState(false);

const onFileInputChange = (event) => {


const currentFiles = event.target.files;

Dept of Information Technology, SVECW Page 53


OUTING MANAGEMENT

if(currentFiles.length === 1){


const file = currentFiles[0];
if(isValidFile(file)){
setImage(file);
open();
}else{
toast.warning(`Wrong file type ${file.type}`, {
position: toast.POSITION.TOP_CENTER,
autoClose: 2000,
});
}
}
}
const onUploadClick = async() =>{
const canvas = avatarEditorRef.current.getImageScaledToCanvas();
setIsLoading(true);
try{
const blob = await getBlob(canvas);
const avatarFileRef = storageRef(storage,`/profiles/${profile.uid}/avatar`);
const uploadAvatarResult = await uploadBytes(avatarFileRef,blob,{
cacheControl : `public,max-age=${3600*24*3}`
});
await uploadAvatarResult;
const downloadUrl = await getDownloadURL(avatarFileRef);
const updates = await getUserUpdate(profile.uid,'avatar',downloadUrl,database);
console.log("udatesAvatar"+updates);
await update(databaseRef(database), updates);

setIsLoading(false);
toast.success('Avatar has been uploaded', {
position: toast.POSITION.TOP_CENTER,
autoClose: 2000,
});

}catch(err){
setIsLoading(false);
toast.error(`Error: ${err.message}`, {
position: toast.POSITION.TOP_CENTER,
autoClose: 2000,
});
}
}
return (
<div className='mt-3 text-center'>
<ProfileAvatar src = {profile.avatar} name = {profile.name} className = "width-200 height-
200 img-fullsize font-huge"/>
Dept of Information Technology, SVECW Page 54
OUTING MANAGEMENT

<div>
<label htmlFor='avatar-upload' className='d-block cursor-pointer padded'>
Select new avatar
<input id='avatar-upload' type="file" className='d-none' accept={fileInputTypes}
onChange={onFileInputChange}/>
</label>
<Modal open={isOpen} onClose={close}>
<Modal.Header>
<Modal.Title>Adjust and upload new avatar</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className='d-flex justify-content-center align-items-center h-100'>
{
image &&
<AvatarEditor
ref = {avatarEditorRef}
image={image}
width={200}
height={200}
border={10}
borderRadius={100}
rotate={0}
/>
}
</div>
</Modal.Body>
<Modal.Footer>
<Button appearance='ghost' block onClick = {onUploadClick} disabled =
{isLoading}>Upload new avatar</Button>
</Modal.Footer>
</Modal>
</div>
</div>
)
}

export default AvatarUploadBtn

DashboardToggle.js:

import React, { useCallback,useEffect } from 'react'


import {Button,Drawer} from 'rsuite';
import DashboardIcon from '@rsuite/icons/Dashboard';
import { useModelState } from '../../misc/custom-hooks';
import { auth,database } from '../../misc/firebase';
import Dashboard from '.';
Dept of Information Technology, SVECW Page 55
OUTING MANAGEMENT

import { signOut } from 'firebase/auth';


import {set,ref} from "firebase/database";
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import {isOfflineForDatabase} from '../../context/ProfileContext';
import {useNavigate} from 'react-router-dom';

const DashboardToggle = () => {


const {isOpen,close,open} = useModelState();
const navigate = useNavigate();
const updateStatus = () => {
const userStatusRef = ref(database, `/status/${auth.currentUser.uid}`);
return set(userStatusRef, isOfflineForDatabase);
};
const onSignOut = useCallback(() => {
const userStatusRef = ref(database, `/status/${auth.currentUser.uid}`);
set(userStatusRef, isOfflineForDatabase).then(() => signOut(auth))
.then(() => {
toast.success('Signed Out', {
position: toast.POSITION.TOP_CENTER, // Align to the center
autoClose: 5000, // Auto-close the alert after 5000 milliseconds (5 seconds)
});
navigate("/signin");
close();
})
.catch((error) => toast.error(`Error: ${error.message}`, {
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
}));

}, [close]);

useEffect(() => {
const handleBeforeUnload = () => {
updateStatus();
};

window.addEventListener('beforeunload', handleBeforeUnload);

return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
};
}, [updateStatus]);
return (
<>

Dept of Information Technology, SVECW Page 56


OUTING MANAGEMENT

<Button block color='blue' appearance='primary' startIcon={<DashboardIcon/>}


onClick={open}>
Dashboard
</Button>

<Drawer open = {isOpen} onClose = {close} placement='left' backdrop>


<Dashboard onSignOut = {onSignOut}/>
</Drawer>
</>
)
}

export default DashboardToggle

index.js:

import React,{useContext} from 'react'


import {Drawer,Button,Divider} from 'rsuite';
import { ProContext } from '../../context/ProfileContext';
import EditableInput from '../EditableInput';
import '../../styles/main.scss';
import {database} from '../../misc/firebase';
import {ref,set,update} from 'firebase/database';
import ProviderBlock from './ProviderBlock';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import AvatarUploadBtn from './AvatarUploadBtn';
import {getUserUpdate} from '../../misc/helper';

const Dashboard = ({onSignOut}) => {


const {profile} = useContext(ProContext);
const onSave = async (newData) => {
try {
const updates = await getUserUpdate(profile.uid, 'name', newData, database);
console.log("updatesDashboard", updates);
await update(ref(database), updates);
toast.success('User name set successfully', {
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
});
} catch (err) {
toast.error(`Error: ${err.message}`, {
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
});
}
Dept of Information Technology, SVECW Page 57
OUTING MANAGEMENT

};

return (
<>
{console.log("profile",profile)}
<Drawer.Header>
<Drawer.Title>
Dashboard
</Drawer.Title>
</Drawer.Header>
<Drawer.Body style={{
margin: 0,
padding: 0,
}}>
<h3>Hey, {profile.name}</h3>
<ProviderBlock/>
<Divider/>
<EditableInput initialValue = {profile.name} onSave = {onSave} label = {<h6
className='mb-2'>Nickname</h6>} name = "nickname"/>
<AvatarUploadBtn/>
<Button block color='red' appearance='primary' style={{ position: 'absolute', bottom: '0'}}
onClick={onSignOut} >
Sign Out
</Button>
</Drawer.Body>
</>
)
}

export default Dashboard;

ProviderBlock.js:

import React,{useState} from 'react';


import {auth} from '../../misc/firebase';
import {Tag,Button} from 'rsuite';
import { FaGoogle } from 'react-icons/fa';
import { GoogleAuthProvider,FacebookAuthProvider,linkWithPopup,unlink} from 'firebase/auth';
import FacebookOfficialIcon from '@rsuite/icons/legacy/FacebookOfficial';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

const ProviderBlock = () => {


const [isConnected,setIsConnected] = useState({
'google.com' : auth.currentUser.providerData.some(data => data.providerId === 'google.com'),

Dept of Information Technology, SVECW Page 58


OUTING MANAGEMENT

'facebook.com' : auth.currentUser.providerData.some(data => data.providerId ===


'facebook.com')
})

const updateIsConnected = (providerId,value) => {


setIsConnected(p => {
return {
...p,
[providerId] : value
}
})
}
// console.log("uid"+" "+auth.currentUser.providerData[0].providerId);
const unlinking = async(providerId) => {
try{
if(auth.currentUser.providerData.length === 1){
throw new Error(`You can not disconnect from ${providerId}`)
}

await unlink(auth.currentUser, providerId);


updateIsConnected(providerId,false);
toast.success(`disconnected from ${providerId}`, {
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
});

}catch(error){
toast.error(`Error: ${error.message}`, {
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
});
}
}
const unlinkGoogle = () => {
unlinking('google.com');
}
const unlinkFacebook = () => {
unlinking('facebook.com');
}
const link = async(provider) => {
try{
await linkWithPopup(auth.currentUser, provider);
toast.success(`Linked to ${provider.providerId}`, {
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
});
Dept of Information Technology, SVECW Page 59
OUTING MANAGEMENT

updateIsConnected(provider.providerId,true);
}catch(error){
toast.error(`Error: ${error.message}`, {
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
});
}
}
const linkGoogle = () => {
const googleProvider = new GoogleAuthProvider();
link(googleProvider);
}
const linkFacebook = () => {
const facebookProvider = new FacebookAuthProvider();
link(facebookProvider);
}
return (
<div>
{
isConnected["google.com"] &&
<Tag color='green' closable onClose={unlinkGoogle}>
<FaGoogle/> Connected
</Tag>
}
{
isConnected["facebook.com"] &&
<Tag color='blue' closable onClose={unlinkFacebook}>
<FacebookOfficialIcon/> Connected
</Tag>
}
<div className='mt-2'>
{
!isConnected["google.com"] &&
<Button block color='green' appearance='primary' onClick={linkGoogle}>
<FaGoogle/> Link To Google
</Button>
}
{
!isConnected["facebook.com"] &&
<Button block color='blue' appearance='primary' onClick={linkFacebook}>
<FacebookOfficialIcon/> Link To Facebook
</Button>
}
</div>
</div>
)
Dept of Information Technology, SVECW Page 60
OUTING MANAGEMENT

export default ProviderBlock;

rooms

ChatRoomList.js:

import React, { useContext } from 'react';


import { Loader, Nav } from 'rsuite';
import RoomItem from './RoomItem';
import '../../styles/main.scss';
import '../../styles/utility.scss';
import { RoomsContext } from '../../context/rooms.context';
import { Link,useLocation } from 'react-router-dom';

const ChatRoomList = ({ aboveElHeight }) => {


const rooms = useContext(RoomsContext);
const location = useLocation();

return (
<div>
<Nav
appearance="subtle"
vertical
reversed
className="overflow-y-scroll custom-scroll"
activeKey={location.pathname}
>
{!rooms && (
<Loader
center
vertical
content="Loading..."
speed="slow"
size="md"
/>
)}
{rooms &&
rooms.length > 0 &&
rooms.map((room) => (
<Nav.Item key={room.id} as={Link} to={`/chat/${room.id}`} eventKey = {`/chat/$
{room.id}`}>
<RoomItem
id={room.id}

Dept of Information Technology, SVECW Page 61


OUTING MANAGEMENT

name={room.name}
createdAt={room.createdAt}
lastMessage={room.lastMessage}
/>
</Nav.Item>
))}
</Nav>
</div>
);
};

export default ChatRoomList;

RoomItem.js:

import React from 'react';


import TimeAgo from 'timeago-react';
import '../../styles/main.scss';
import ProfileAvatar from '../ProfileAvatar';

const RoomItem = ({ id, name, createdAt,lastMessage }) => {


return (
<div>
<div className="d-flex justify-content-between align-items-center">
<h4 className="text-disappear">{name}</h4>
{/* <TimeAgo
datetime={lastMessage? new Date(lastMessage.createdAt) : new Date(createdAt)}
className="time-ago font-normal text-black-45"/> */}
</div>
<div className="d-flex align-items-center text-black-70">
{
lastMessage ?
<>
<div className='d-flex align-items-center'>
<ProfileAvatar src={lastMessage.author.avatar} name={lastMessage.author.name}
size="sm"/>
</div>
<div className='text-disappear ml-2'>
<div className='italic'>
{lastMessage.author.name}
</div>
<span>
{lastMessage.text || lastMessage.file.name}
</span>
</div>
</> :
Dept of Information Technology, SVECW Page 62
OUTING MANAGEMENT

<span>No messages yet....</span>


}

</div>
</div>
);
};

export default RoomItem;

CreateRoomBtnModel.js:

import React,{useCallback, useRef, useState} from 'react'


import {Button,Modal,Form,Input,Schema} from 'rsuite';
import CreativeIcon from '@rsuite/icons/Creative';
import { useModelState } from '../misc/custom-hooks';
import '../styles/main.scss';
import { serverTimestamp,ref,push,set } from 'firebase/database';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { auth, database } from '../misc/firebase';

const Textarea = React.forwardRef((props, ref) => <Input {...props} as="textarea" ref={ref} />);

const INITIAL_FORM = {
name : "",
description : ""
}

const {StringType} = Schema.Types;

const model = Schema.Model({


name : StringType().isRequired("Chat name is required"),
description : StringType().isRequired("Description is required")
})

const CreateRoomBtnModel = () => {

const {isOpen,open,close} = useModelState();


const [formValue,setFormValue] = useState(INITIAL_FORM);
const [isLoading,setIsLoading] = useState(false);
const formRef = useRef();
const onFormChange = useCallback((value) => {

Dept of Information Technology, SVECW Page 63


OUTING MANAGEMENT

setFormValue(value);
},[]);
const onSubmit = async() => {
if(!formRef.current.check()){
return;
}
setIsLoading(true);
const newRoomdata = {
...formValue,
createdAt : serverTimestamp(),
admins : {
[auth.currentUser.uid] : true,
}
}
try{
const roomsRef = await ref(database, 'rooms');
const newRoomRef = push(roomsRef);
await set(newRoomRef, newRoomdata);

toast.info(`${formValue.name} has been created`, {


position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
});

setIsLoading(false);
setFormValue(INITIAL_FORM);
close();

}catch(error){
setIsLoading(false);
toast.error(`Error: ${error.message}`, {
position: toast.POSITION.TOP_CENTER,
autoClose: 3000,
});
}
}
return (
<div className='mt-1'>
<Button block color='green' appearance='primary' onClick = {open}>
<CreativeIcon/> Create new chat room
</Button>
<Modal open = {isOpen} onClose = {close}>
<Modal.Header>
<Modal.Title>
New chat room
Dept of Information Technology, SVECW Page 64
OUTING MANAGEMENT

</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form fluid onChange = {onFormChange} formValue = {formValue} model = {model}
ref={formRef}>
<Form.Group>
<Form.ControlLabel>Room name</Form.ControlLabel>
<Form.Control name = "name" placeholder = 'Enter chat room
name.....'></Form.Control>
</Form.Group>
<Form.Group>
<Form.ControlLabel>Description</Form.ControlLabel>
<Form.Control rows={5} name="description" accepter={Textarea} placeholder =
'Enter room description'></Form.Control>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button block appearance='primary' onClick = {onSubmit} disabled = {isLoading}>
Create new chat room
</Button>
</Modal.Footer>
</Modal>
<ToastContainer />
</div>
)
}

export default CreateRoomBtnModel

EditableInput.js:

import React, { useCallback, useState } from 'react'


import {Input,InputGroup} from 'rsuite';
import EditIcon from '@rsuite/icons/Edit';
import CloseIcon from '@rsuite/icons/Close';
import CheckIcon from '@rsuite/icons/Check';

const EditableInput = ({initialValue,onSave,label = null,placeholder = "Write Your


name",emptyMsg = "Input is empty",wrapperClassName = "",...inputProps}) => {
const [input,setInput] = useState(initialValue);
const [isEditable,setIsEditable] = useState(false);

const onInputChange = useCallback((value)=>{


setInput(value);
},[]);
Dept of Information Technology, SVECW Page 65
OUTING MANAGEMENT

const onEditClick = useCallback(()=>{


console.log("called");
setIsEditable(p => !p);
setInput(initialValue);
},[initialValue]);

const onSaveClick = async() => {


const trimmed = input.trim();
if(trimmed === ''){
alert(emptyMsg);
}

if(trimmed != initialValue){
await onSave(trimmed);
}

setIsEditable(false);
}

return (
<div className={wrapperClassName}>
{label}
<InputGroup>
<Input {...inputProps} disabled = {!isEditable} placeholder={placeholder} value = {input}
onChange={onInputChange}/>
<InputGroup.Button onClick={onEditClick}>
{
isEditable ? <CloseIcon /> : <EditIcon />
}
</InputGroup.Button>
{isEditable &&
<InputGroup.Button onClick={onSaveClick}>
<CheckIcon/>
</InputGroup.Button>}
</InputGroup>
</div>
)
}

export default EditableInput

PresenceDot.js:

import React from 'react';


Dept of Information Technology, SVECW Page 66
OUTING MANAGEMENT

import {usePresence} from '../misc/custom-hooks';


import {Whisper,Tooltip,Badge} from 'rsuite';

const getColor = (presence) => {


if(!presence){
return 'grey';
}
switch(presence.state){
case "online":
return 'green';
case "offline":
return 'red';
default:
return 'grey';
}
}

const getText = (presence) => {

if(!presence){
return "Unknown state";
}
return presence.state === 'online' ? 'Online' : `Last online ${new
Date(presence.last_changed).toLocaleDateString()}`;
}

const PresenceDot = ({uid}) => {


console.log(uid);
const presence = usePresence(uid);
console.log("pre"+" "+presence);
return (
<Whisper placement="top" controlId="control-id-hover" trigger="hover" speaker={<Tooltip>
{getText(presence)}
</Tooltip>}>
<Badge className='cursor-pointer' style={{backgroundColor:getColor(presence)}}/>
</Whisper>
)
}

export default PresenceDot

PrivateRoute.js:

import React,{useContext} from 'react';


import {Navigate} from 'react-router-dom';
import Home from '../pages/Home/index';
Dept of Information Technology, SVECW Page 67
OUTING MANAGEMENT

import { ProContext } from '../context/ProfileContext';


import {Container,Loader} from 'rsuite';

const PrivateRoute = () => {

const {profile,isLoading} = useContext(ProContext);

if(isLoading && !profile){


return (
<div>
<Container>
<Loader center vertical size="md" content="Loading..." speed="slow" />
</Container>
</div>
);
}
if(!isLoading && !profile){
return <Navigate to = "/signin"/>
}
return (
<div>
{console.log("profile"+" "+profile)}
{profile!=null ? <Home/> : <Navigate to="/signin"/>}
</div>
);
};

export default PrivateRoute;

ProfileAvatar.js :

import React from 'react'


import {Avatar} from 'rsuite';
import { getNameInitials } from '../misc/helper';

const ProfileAvatar = ({name,...avatarProps}) => {


return (
<div>
<Avatar circle {...avatarProps}>
{
getNameInitials(name)
}
</Avatar>
</div>
)
Dept of Information Technology, SVECW Page 68
OUTING MANAGEMENT

export default ProfileAvatar;

PublicRoute.js :

import React,{useContext} from 'react';


import {Navigate} from 'react-router-dom';
import SignIn from '../pages/SignIn';
import { ProContext } from '../context/ProfileContext';
import {Container,Loader} from 'rsuite';

const PublicRoute = () => {

const {profile,isLoading} = useContext(ProContext);

if(isLoading && !profile){


return (
<div>
<Container>
<Loader center vertical size="md" content="Loading..." speed="slow" />
</Container>
</div>
);
}
if(!isLoading && profile){
return <Navigate to = "/"/>
}
return (
<div>
{console.log("profile"+" "+profile)}
{profile!=null ? <Navigate to="/"/> : <SignIn/>}
</div>
);
};

export default PublicRoute;

Sidebar.js:

import React, { useRef,useState,useEffect } from 'react'


import DashboardToggle from '../components/dashboard/DashboardToggle';
import CreateRoomBtnModel from './CreateRoomBtnModel';
import {Divider} from 'rsuite';
import ChatRoomList from './rooms/ChatRoomList';
Dept of Information Technology, SVECW Page 69
OUTING MANAGEMENT

import '../styles/main.scss';

const Sidebar = () => {


const topSidebarRef = useRef();
const [height,setHeight] = useState(0);
useEffect(()=>{
if(topSidebarRef.current){
setHeight(topSidebarRef.current.getBoundingClientRect().height)
}
},[topSidebarRef]);
return (
<div className='h-100 pt-2'>
<div ref = {topSidebarRef}>
<DashboardToggle/>
<CreateRoomBtnModel/>
<Divider>Join conversation</Divider>
</div>
<ChatRoomList aboveElHeight = {height}/>
</div>
)
}

export default Sidebar;

Context

current-room.context.js:

import React from "react";


import { createContext,useContextSelector } from "use-context-selector";

const CurrentRoomContext = createContext();

export const CurrentRoomProvider = ({children,data}) => {


return <CurrentRoomContext.Provider value =
{data}>{children}</CurrentRoomContext.Provider>
}

export const useCurrentRoom = selector => useContextSelector(CurrentRoomContext, selector);

Dept of Information Technology, SVECW Page 70


OUTING MANAGEMENT

ProfileContext.js:

import React,{createContext,useEffect,useState} from 'react';


import { onAuthStateChanged } from 'firebase/auth';
import {auth,database} from '../misc/firebase';
import {ref,onValue,off,serverTimestamp,onDisconnect,set} from 'firebase/database';

export const isOfflineForDatabase = {


state: 'offline',
last_changed: serverTimestamp(),
};

const isOnlineForDatabase = {
state: 'online',
last_changed: serverTimestamp(),
};

export const ProContext = createContext();


export const ProfileContext = ({children}) => {
const [profile,setProfile] = useState(null);
const [isLoading,setIsLoading] = useState(true);

useEffect(() => {
let userRef = null;
let userStatusRef;

const unsub = onAuthStateChanged(auth, (user) => {


console.log('Auth State Changed:', user);
if (user) {
console.log("userIdForRooms"+" "+user.uid);
userStatusRef = ref(database,`/status/${user.uid}`);
userRef = ref(database, `/profiles/${user.uid}`);
const onValueChange = onValue(userRef, async (snapshot) => {
const data = snapshot.val();

if (data) {
const { name, createdAt,avatar } = data;
console.log(name, createdAt);
const userData = {
name: name,
createdAt: createdAt,
avatar : avatar,
email: user.email,
Dept of Information Technology, SVECW Page 71
OUTING MANAGEMENT

uid: user.uid,
};
setProfile(userData);
console.log("username in pc"+" "+userData.name)
}else {
setProfile(null);
}
setIsLoading(false);
});

const connectedRef = ref(database, '.info/connected');


onValue(connectedRef, (snapshot) => {
if (!!snapshot.val() === false) {
return;
}
const userStatusDatabaseRefOnDisconnect = onDisconnect(userStatusRef);
set(userStatusDatabaseRefOnDisconnect, isOfflineForDatabase).then(() => {
set(userStatusRef, isOnlineForDatabase);
});
});
} else {
if (userRef) {
off(userRef);
}
if(userStatusRef){
off(userStatusRef);
}
const connectedRef = ref(database, '.info/connected');
off(connectedRef);
setProfile(null);
setIsLoading(false);
}
});

return () => {
unsub();
const connectedRef = ref(database, '.info/connected');
off(connectedRef);
if (userRef) {
off(userRef);
}
if(userStatusRef){
off(userStatusRef);
}
};
}, []);
Dept of Information Technology, SVECW Page 72
OUTING MANAGEMENT

return(
<div>
<ProContext.Provider value = {{profile,isLoading}}>
{children}
</ProContext.Provider>
</div>
)
}

rooms.context.js:

import React,{createContext, useEffect, useState} from "react";


import {database} from '../misc/firebase';
import {ref,onValue,off} from 'firebase/database';
import { transformToArrWithId } from "../misc/helper";

export const RoomsContext = createContext();

export const RoomsProvider = ({children}) => {


const [rooms,setRooms] = useState(null);
useEffect(()=>{
const roomListRef = ref(database,'rooms');
const onValueChange = onValue(roomListRef,(snapshot)=>{
const data = transformToArrWithId(snapshot.val());
setRooms(data);
})
return () => {
off(roomListRef);
}
},[]);
return(
<div>
<RoomsContext.Provider value = {rooms}>
{children}
</RoomsContext.Provider>
</div>
)
}

Dept of Information Technology, SVECW Page 73


OUTING MANAGEMENT

misc

custom-hooks.js:

import { useCallback, useState,useEffect,useRef } from "react";


import {database} from './firebase';
import {ref,onValue,off} from "firebase/database";

export function useModelState(defaultValue = false){


const [isOpen,setIsOpen] = useState(defaultValue)

const open = useCallback(() => setIsOpen(true),[]);


const close = useCallback(() => setIsOpen(false),[]);

return {isOpen,open,close}
}

export const useMediaQuery = (query) => {


const [matches, setMatches] = useState(() => window.matchMedia(query).matches);

useEffect(() => {
const queryList = window.matchMedia(query);
setMatches(queryList.matches);

const listener = (evt) => setMatches(evt.matches);

queryList.addEventListener('change', listener);
return () => queryList.removeEventListener('change', listener);
}, [query]);

return matches;
};

export function usePresence(uid){


const [presence,setPresence] = useState(null);
useEffect(() => {
const userStatusRef = ref(database,`/status/${uid}`);
onValue(userStatusRef,(snapshot)=>{
if(snapshot.exists()){
const data = snapshot.val();
setPresence(data);
}
})
return ()=>{

Dept of Information Technology, SVECW Page 74


OUTING MANAGEMENT

off(userStatusRef);
}
}, [uid]);
return presence;
}

export function useHover() {


const [value, setValue] = useState(false);
const ref = useRef(null);
const handleMouseOver = () => setValue(true);
const handleMouseOut = () => setValue(false);
useEffect(
() => {
const node = ref.current;
if (node) {
node.addEventListener('mouseover', handleMouseOver);
node.addEventListener('mouseout', handleMouseOut);
}
return () => {
node.removeEventListener('mouseover', handleMouseOver);
node.removeEventListener('mouseout', handleMouseOut);
};
},
[ref.current] // Recall only if ref changes
);
return [ref, value];
}

firebase.js :

import { initializeApp } from 'firebase/app';


import { getAuth } from 'firebase/auth';
import { getDatabase } from 'firebase/database';
import { getStorage } from 'firebase/storage';

const config = {
apiKey: "AIzaSyATBnXZ-u9eC0AeOPPPiRO_mebvGcRSGrI",
authDomain: "chatroomhub-5ffa3.firebaseapp.com",
databaseURL: "https://chatroomhub-5ffa3-default-rtdb.asia-southeast1.firebasedatabase.app",
projectId: "chatroomhub-5ffa3",
storageBucket: "chatroomhub-5ffa3.appspot.com",
messagingSenderId: "600693016942",
appId: "1:600693016942:web:5812a2d907226b26db197f"
};

const app = initializeApp(config);


Dept of Information Technology, SVECW Page 75
OUTING MANAGEMENT

const auth = getAuth(app);


const database = getDatabase(app);
const storage = getStorage(app);

export { auth,database,storage };

helper.js :

import { ref, orderByChild, equalTo, query, get } from "firebase/database";

export function getNameInitials(name){


const splitName = name.toUpperCase().split(' ');
if(splitName.length >= 2){
return splitName[0][0] + splitName[1][0];
}
return splitName[0][0];
}

export function transformToArrWithId(snapVal){


return snapVal ? Object.keys(snapVal).map(roomId => {
return {...snapVal[roomId],id : roomId};
}) : []
}

export async function getUserUpdate(userId, keyToUpdate, value, db) {


const updates = {};
updates[`/profiles/${userId}/${keyToUpdate}`] = value;

const messagesRef = ref(db, 'messages');


const queryGet = query(messagesRef, orderByChild('author/uid'), equalTo(userId));
const getMsgs = get(queryGet);

const roomsRef = ref(db, 'rooms');


const roomsGet = query(roomsRef, orderByChild('lastMessage/author/uid'), equalTo(userId));
const getRooms = get(roomsGet);
console.log(getMsgs+"and"+getRooms);
const [mSnap,rSnap] = await Promise.all([getMsgs,getRooms]);
mSnap.forEach(msgSnap => {
updates[`/messages/${msgSnap.key}/author/${keyToUpdate}`] = value;
})
rSnap.forEach(roomSnap => {
updates[`/rooms/${roomSnap.key}/lastMessage/author/${keyToUpdate}`] = value;
})

return updates;
}
Dept of Information Technology, SVECW Page 76
OUTING MANAGEMENT

export function transformToArr(snapVal){


return snapVal ? Object.keys(snapVal) : [];
}

export function groupBy(array,groupingKeyFn){


return array.reduce((result,item)=>{
const groupingKey = groupingKeyFn(item);
if(!result[groupingKey]){
result[groupingKey] = [];
}
result[groupingKey].push(item);
return result;
},{})
}

Pages

Home

Chat.js:

import React,{useContext} from 'react';


import {useParams} from 'react-router-dom';
import {Loader} from 'rsuite';
import ChatTop from '../../components/chat-window/top/index';
import ChatBottom from '../../components/chat-window/bottom/index';
import Messages from '../../components/chat-window/messages/index';
import '../../styles/main.scss';
import { RoomsContext } from '../../context/rooms.context';
import { CurrentRoomProvider } from '../../context/current-room.context';
import { auth } from '../../misc/firebase';
import {transformToArr} from '../../misc/helper';

const Chat = () => {

const {chatId} = useParams();


const rooms = useContext(RoomsContext);
if(!rooms){
return <Loader center vertical size = "md" content = "Loading..." speed='slow' ></Loader>
}

const currentRoom = rooms.find(room => room.id === chatId);


const {name,description} = currentRoom;
const admins = transformToArr(currentRoom.admins);

Dept of Information Technology, SVECW Page 77


OUTING MANAGEMENT

const isAdmin = admins.includes(auth.currentUser.uid);


const currentRoomData = {
name,description,admins,isAdmin
}
if(!currentRoom){
return <h6 className='text-center mt-page'>Chat {chatId} not found</h6>
}

return (
<CurrentRoomProvider data = {currentRoomData}>
<div className='chat-top'>
<ChatTop/>
</div>
<div className='chat-middle'>
<Messages/>
</div>
<div className='chat-bottom' style={{ position: 'fixed', bottom: 0, width: '100%' }}>
<ChatBottom/>
</div>
</CurrentRoomProvider>
)
}

export default Chat;

index.js:

import React,{useState,useEffect} from 'react';


import {Grid,Row,Col} from 'rsuite';
import Sidebar from '../../components/Sidebar'
import '../../styles/main.scss';
import { RoomsProvider } from '../../context/rooms.context';
import { Routes,Route,useMatch,useLocation } from 'react-router-dom';
import Chat from './Chat';

const Home = () => {


const { pathname } = useLocation();
const match = useMatch('/chat/:chatId');
const isExact = match ? pathname === match.pathname : false;
const [isDesktop, setIsDesktop] = useState(window.innerWidth > 768); // Adjust the threshold as
needed

useEffect(() => {
const handleResize = () => {
setIsDesktop(window.innerWidth > 768); // Adjust the threshold as needed
};
Dept of Information Technology, SVECW Page 78
OUTING MANAGEMENT

// Add event listener for window resize


window.addEventListener('resize', handleResize);
console.log("desktop"+" "+isDesktop);
// Cleanup the event listener on component unmount
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
const canRenderSidebar = isDesktop || isExact;

return(
<div >
<RoomsProvider>
<Grid fluid className='h-100'>
<Row className='h-100'>
{canRenderSidebar &&
(<Col xs = {24} md = {8} className='h-100'>
<Sidebar/>
</Col>
)}
<Routes>
<Route path='/chat/:chatId' element={
<React.Fragment>
<Col xs={24} md={16} className='h-100'>
{console.log("hello in chat application")}
<Chat />
</Col>
</React.Fragment>
}/>
<Route path='/' element={
<React.Fragment>
{
isDesktop && (<Col xs = {24} md = {16} className='h-100'>
<h6 className='text-center mt-page'>Please Select Chat</h6>
</Col>
)}
</React.Fragment>
}/>
</Routes>

</Row>
</Grid>
</RoomsProvider>
</div>
)
Dept of Information Technology, SVECW Page 79
OUTING MANAGEMENT

export default Home;

logins

InputControl

InputControl.js :

import React from 'react'


import styles from './InputControl.module.css';

const InputControl = (props) => {


return (
<div className={styles.container}>
{props.label && <label>{props.label}</label>}
<input type = {props.label === "Password" ? "password" : "text"} {...props}/>
</div>
)
}

export default InputControl

InputControl.css :

.container{
display: flex;
flex-direction: column;
gap: 8px;
}
.container label{
font-weight: 500;
font-size: 1rem;
color: #4b4b4b;
}

.container input{
border-radius: 5px;
border: 1px solid #eee;
outline: none;
padding: 10px 15px;
color: #000;
}
.container input:hover{
Dept of Information Technology, SVECW Page 80
OUTING MANAGEMENT

border-color:#ccc ;
}
.container input:focus{
border-color:#9900ff ;
}

Login

Login.js:

import React,{useState} from 'react'


import styles from './LogIn.module.css';
import InputControl from '../InputControl/InputControl';
import {Link,useNavigate} from 'react-router-dom';
import {auth,database} from '../../../misc/firebase';
import {signInWithEmailAndPassword,updateProfile} from 'firebase/auth';
import {ref,set,get,serverTimestamp} from "firebase/database"

const LogIn = () => {


const navigate = useNavigate();
const [values,setValues] = useState({
email : "",
pass : ""
})

const[errorMsg,setErrorMsg] = useState("");

const[submitButtonDisabled,setSubmitButtonDisabled] = useState(false);

const handleSubmission = () => {


if(!values.email || !values.pass){
setErrorMsg("Fill all the fields");
return;
}
setErrorMsg("");
setSubmitButtonDisabled(true);
console.log(values);
signInWithEmailAndPassword(auth,values.email,values.pass).then(async(res) => {
setSubmitButtonDisabled(false);
setErrorMsg("");
const user = res.user;
console.log("user in login"+user.displayName);
const userRef = ref(database, `/profiles/${user.uid}`);
const snapshot = await get(userRef);
if (!snapshot.exists()) {

Dept of Information Technology, SVECW Page 81


OUTING MANAGEMENT

await set(userRef, {
name: user.displayName,
email: user.email,
createdAt: serverTimestamp(),
});
}
navigate("/");
}).catch((err)=>{
setSubmitButtonDisabled(false)
setErrorMsg(err.message);
})
}
return (
<div className={styles.container}>
<div className={styles.innerBox}>
<h1 className={styles.heading}>Login</h1>
<InputControl label = "Email" placeholder = "Enter email address"
onChange={(event)=>
setValues((prev)=>({...prev,email:event.target.value}))
}/>
<InputControl label = "Password" placeholder = "Enter password"
onChange={(event)=>
setValues((prev)=>({...prev,pass:event.target.value}))
}/>
<div className={styles.footer}>
<b className={styles.error}>{errorMsg}</b>
<button onClick={handleSubmission}
disabled={submitButtonDisabled}>Login</button>
<p>Already have an account?{" "}
<span><Link to = "/signin">LogOut</Link></span>
</p>
</div>
</div>
</div>
)
}

export default LogIn

LogIn.module.css:

.container{
height: 100%;
min-height: 100vh;
width: 100%;
background:linear-gradient(to right,#9900ff,#cc80ff);
Dept of Information Technology, SVECW Page 82
OUTING MANAGEMENT

display:flex;
justify-content: center;
align-items: center;
}
.innerBox{
min-width: 480px;
height: fit-content;
width: fit-content;
background-color: #fff;
box-shadow: 1px 1px 4px rgba(0,0,0,0.2);
padding: 30px;
border-radius: 10px;
display: flex;
flex-direction: column;
gap: 30px;
}

.footer{
display: flex;
flex-direction: column;
gap: 20px;
}
.footer.error{
font-weight: bold;
flex-direction: column;
gap: 20px;
color: #ff3300;
text-align: center;
}
.footer button{
outline: none;
border: none;
background-color: #9900ff;
color: #fff;
border-radius: 5px;
font-weight: bold;
font-size: 1rem;
padding: 10px 16px;
width: 100%;
transition: 100ms;
}
.footer button:disabled{
background-color: gray !important;
}
.footer button:hover{
background-color: #aa2aff;
Dept of Information Technology, SVECW Page 83
OUTING MANAGEMENT

}
.footer p{
font-weight: 700;
color: #000;
}
.footer p span a{
font-weight: bold;
color: #9900ff;
letter-spacing: 1px;
font-size: 1rem;
text-decoration: none;
}

SignUp

SignUp.js:

import React, { useState } from 'react'


import styles from './SignUp.module.css';
import InputControl from '../InputControl/InputControl';
import {Link,useNavigate} from 'react-router-dom';
import {auth} from '../../../misc/firebase';
import {createUserWithEmailAndPassword,updateProfile} from 'firebase/auth';
import '../../../pages/Logins.css';

const SignUp = () => {


const navigate = useNavigate();
const [values,setValues] = useState({
name : "",
email : "",
pass : ""
})

const[errorMsg,setErrorMsg] = useState("");

const[submitButtonDisabled,setSubmitButtonDisabled] = useState(false);

const handleSubmission = () => {


if(!values.name || !values.email || !values.pass){
setErrorMsg("Fill all the fields");
return;
}
setErrorMsg("");
setSubmitButtonDisabled(true);

Dept of Information Technology, SVECW Page 84


OUTING MANAGEMENT

console.log(values);
createUserWithEmailAndPassword(auth,values.email,values.pass).then(async(res) => {
setSubmitButtonDisabled(false);
const user = res.user;
await updateProfile(user,{
displayName : values.name
});
setErrorMsg("");

}).catch((err)=>{
setSubmitButtonDisabled(false)
setErrorMsg(err.message);
})
}

return (

<div className={styles.container}>
<div className={styles.innerBox}>
<h1 className={styles.heading}>SignUp</h1>
<InputControl label = "Name" placeholder = "Enter your name" onChange={(event)=>
setValues((prev)=>({...prev,name:event.target.value}))
}/>
<InputControl label = "Email" placeholder = "Enter email address" onChange={(event)=>
setValues((prev)=>({...prev,email:event.target.value}))
}/>
<InputControl label = "Password" placeholder = "Enter password" onChange={(event)=>
setValues((prev)=>({...prev,pass:event.target.value}))
}/>
<div className={styles.footer}>
<b className={styles.error}>{errorMsg}</b>
<button onClick={handleSubmission} disabled =
{submitButtonDisabled}>SignUp</button>
<p>Already have an account?{" "}
<span><Link to = "/login">LogIn</Link></span>
</p>
</div>
</div>
</div>

)
}

export default SignUp

Dept of Information Technology, SVECW Page 85


OUTING MANAGEMENT

SignUp.module.css:

.container{
height: 100%;
min-height: 100vh;
width: 100%;
background:linear-gradient(to right,#9900ff,#cc80ff);
display:flex;
justify-content: center;
align-items: center;
}
.innerBox{
min-width: 480px;
height: fit-content;
width: fit-content;
background-color: #fff;
box-shadow: 1px 1px 4px rgba(0,0,0,0.2);
padding: 30px;
border-radius: 10px;
display: flex;
flex-direction: column;
gap: 30px;
}

.footer{
display: flex;
flex-direction: column;
gap: 20px;
}
.footer.error{
font-weight: bold;
flex-direction: column;
gap: 20px;
color: #ff3300;
text-align: center;
}
.footer button{
outline: none;
border: none;
background-color: #9900ff;
color: #fff;
border-radius: 5px;
Dept of Information Technology, SVECW Page 86
OUTING MANAGEMENT

font-weight: bold;
font-size: 1rem;
padding: 10px 16px;
width: 100%;
transition: 100ms;
}
.footer button:disabled{
background-color: gray !important;
}
.footer button:hover{
background-color: #aa2aff;
}
.footer p{
font-weight: 700;
color: #000;
}
.footer p span a{
font-weight: bold;
color: #9900ff;
letter-spacing: 1px;
font-size: 1rem;
text-decoration: none;
}

Logins.css:

.app-container {
margin: 20px;
}

.top-right-buttons {
display: flex;
justify-content: flex-end;
}

.button1{
width: auto;
margin-top: 7px;
margin-right: 20px;
padding: 5px 10px;
cursor: pointer;
color: rgb(2, 2, 24);
font-weight: bolder;
font-size: larger;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
Dept of Information Technology, SVECW Page 87
OUTING MANAGEMENT

background-color: white;
border: 2px solid rgb(2, 2, 24);
border-radius: 25px;
}

.button2 {
margin-top: 7px;
margin-right: 13px;
padding: 5px 10px;
cursor: pointer;
color: rgb(2, 2, 24);
font-weight: bolder;
font-size: larger;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
background-color: white;
border: 2px solid rgb(2, 2, 24);
border-radius: 25px;
}

.button1:hover {
background-color: black;
color: white;
border: 2px solid white;
border-radius: 25px;
}

.button2:hover {
background-color: black;
color: white;
border: 2px solid white;
border-radius: 25px;
}

NavigateButtons.js:

import React from 'react';


import styled from 'styled-components';
import {useNavigate} from 'react-router-dom';
import './Logins.css';

// buttonface
const theme = {
'b': {
default: 'White',
hover: 'Azure', // Change this to the desired hover color
Dept of Information Technology, SVECW Page 88
OUTING MANAGEMENT

},
};

const Button = styled.button`


background-color: ${props => theme[props.theme].default};
color: Black;
border:none;
padding: 6px 20px;
border-radius: 10px;
margin: 10px 10px 7px 0;
cursor: pointer;
position:relative;
font: 400 16px system-ui;
transition: background-color 250ms ease;
text-rendering: geometricPrecision;
display: inline-block;
// text-indent: 0px;
// text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
// border: 0.7px solid Dimgray; solid Dimgray

&:before {
content: '';
position: absolute;
width: 100%;
height: 0.8px; /* Set the thickness of the underline */
bottom: 0;
left: 0;
background-color: Darkgreen; /* Set the color of the underline */
transform: scaleX(0); /* Initially hide the underline */
transform-origin: bottom right;
transition: transform 0.4s ease-out;
}
&:hover{
color: DarkGreen;
}
&:hover:before {
transform: scaleX(1); /* Show the underline on hover */
transform-origin: bottom left;
}
}

`;
// &:hover {
// background-color: ${props => theme[props.theme].hover};
// color: Dimgray;
// border-radius: 20px;
Dept of Information Technology, SVECW Page 89
OUTING MANAGEMENT

// }
// opacity: 1;
// border-color: Dimgray;
// box-shadow: 3px 3px 2px ;
// Dimgray
//lightgrey
const ButtonGroup = styled.div`
display: flex;
justify-content: flex-en;
position: absolute;
top:10px;
right: 10px;
`;

Button.defaultProps = {
theme: 'b',
};

export default function App() {


const navigate = useNavigate();

const handleSignInClick = () => {


navigate('/login');
};

const handleSignUpClick = () => {


navigate('/signup');
};
return (
<ButtonGroup>
<Button onClick = {handleSignInClick}>LogIn</Button>
<Button onClick = {handleSignUpClick}>SignUp</Button>
</ButtonGroup>
);
}

SignIn.js:

import React from 'react';


import {Container,Grid,Row,Col,Panel,Button} from 'rsuite';
import "../styles/main.scss";
import { GoogleAuthProvider,FacebookAuthProvider,signInWithPopup} from 'firebase/auth';
import FacebookOfficialIcon from '@rsuite/icons/legacy/FacebookOfficial';
import { FaGoogle } from 'react-icons/fa';
import { auth,database } from '../misc/firebase';
Dept of Information Technology, SVECW Page 90
OUTING MANAGEMENT

import Swal from 'sweetalert2';


import { serverTimestamp } from 'firebase/database';
import { ref, set, get } from 'firebase/database';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import NavigateButtons from './NavigateButtons';

const SignIn = () => {

const signInWithProvider = async (provider) => {


try {
const result = await signInWithPopup(auth, provider);
console.log(result);
const user = result.user;
const userRef = ref(database, `/profiles/${user.uid}`);
const snapshot = await get(userRef);
if (!snapshot.exists()) {
await set(userRef, {
name: user.displayName,
email: user.email,
createdAt: serverTimestamp(),
});
}
Swal.fire({
icon: 'success',
title: 'Success',
text: 'You have successfully signed in!',
});
} catch (error) {
Swal.fire({
icon: 'error',
title: 'Error',
text: `Sign-in error: ${error.message}`,
});
}
};

const onFacebookSignIn = () => {


const facebookProvider = new FacebookAuthProvider();
signInWithProvider(facebookProvider);
}

const onGoogleSignIn = () => {


const googleProvider = new GoogleAuthProvider();
signInWithProvider(googleProvider);
Dept of Information Technology, SVECW Page 91
OUTING MANAGEMENT

};

return(
<div>
<NavigateButtons/>
<Container>
<Grid className='mt-page'>
<Row>
<Col xs = {24} md = {12} mdOffset={6}>
<Panel>
<div className = "text-center">
<h2>Welcome To Chat</h2>
<p>Progressive chat platform for neophytes</p>
</div>
<div className='mt-3'>
<Button block color = "blue" appearance = "primary" startIcon =
{<FacebookOfficialIcon style={{ fontSize: '2em' }}/>} onClick={onFacebookSignIn}>
Continue with facebook
</Button>
<Button block color = "green" appearance = "primary"
startIcon={<FaGoogle style={{ fontSize: '1.5em' }} />} onClick={onGoogleSignIn}>
Continue with google
</Button>
</div>
</Panel>
</Col>
</Row>
</Grid>
</Container>
<ToastContainer />
</div>
)
}

export default SignIn;

styles

main.scss:

@import 'override';
@import 'utility';
@import 'utility_colors';

body {

Dept of Information Technology, SVECW Page 92


OUTING MANAGEMENT

margin: 0;
// font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
// 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
// sans-serif;
font-family: 'Poppins', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
// background-image: url('');
// background-repeat: no-repeat;
// background-size: cover;
background-color: #1a1d22;
}

html,
body,
#root,
#root > div {
height: 100%;
}

.overflow-y-scroll {
overflow-y: auto;
}

.custom-scroll {
/* Customize the scrollbar appearance */
scrollbar-width: thin;
scrollbar-color: #ccc #f0f0f0;
height: calc(100% - 108px);

/* For WebKit browsers */


&::-webkit-scrollbar {
width: 8px;
}

&::-webkit-scrollbar-thumb {
background-color: #ccc;
border-radius: 4px;
}

&::-webkit-scrollbar-track {
background-color: #f0f0f0;
}
}

.room-item {
Dept of Information Technology, SVECW Page 93
OUTING MANAGEMENT

display: flex;
flex-direction: column; /* Ensures the children stack vertically */
}

.time-ago {
margin-left: 290px !important;
}

.chat-room-list-wrapper {
height: 100%;
}

.img-fullsize {
*{
width: auto !important;
height: auto !important;
}
}

.chat-top,
.chat-middle,
.chat-bottom {
margin: 0;
padding: 0;
}

.chat-top,
.chat-bottom {
display: flex;
flex-direction: column;
justify-content: center;
}

$chat-t: 75px;
$chat-b: 65px;

.chat-top {
height: $chat-t;
}

.chat-bottom {
height: $chat-b;
}

.chat-middle {
height: calc(100% - #{$chat-t} - #{$chat-b});
Dept of Information Technology, SVECW Page 94
OUTING MANAGEMENT

.msg-list {
padding: 0;
margin: 0;
height: 100%;
overflow-y: auto;
list-style-type: none;

li {
&:last-child {
margin-bottom: 0 !important;
padding-bottom: 0 !important;
}
}
}

.animate-blink {
animation: blink normal 1.5s infinite ease-in-out;
color: red !important;
@keyframes blink {
0% {
opacity: 1;
}
50% {
opacity: 0.3;
}
100% {
opacity: 1;
}
}
}

#chat-container {
max-width: 400px;
margin: auto;
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

#chat-input {
width: 70%;
padding: 8px;
margin-right: 8px;
Dept of Information Technology, SVECW Page 95
OUTING MANAGEMENT

border: 1px solid #ccc;


border-radius: 4px;
box-sizing: border-box;
}

#send-button {
padding: 8px;
border: 1px solid #4CAF50;
background-color: #4CAF50;
color: white;
border-radius: 4px;
cursor: pointer;
}

.lucky1{
overflow: hidden;
}

.lucky2{
display: inline-block;
visibility: visible;
}

.input-container {
display: flex;
}

.input-container > * {
flex: 1;
}

.rs-input-group{
width: 66%;
}

override.scss:

.rs-drawer-body {
margin: 20px;
}

.rs-input[disabled] {
color: #575757;
}

.rs-modal {
Dept of Information Technology, SVECW Page 96
OUTING MANAGEMENT

max-width: 100%;
padding-left: 10px;
padding-right: 10px;
}

.rs-modal-body {
padding-top: 5px;
padding-bottom: 5px;
margin-top: 10px;
margin-bottom: 10px;
min-height: 250px;
}

textarea.rs-input {
min-width: 160px;
min-height: 35px;
}

.rs-popover {
max-height: 70vh;
min-width: 300px;
overflow-y: auto;
}

.w-100 {
.rs-uploader-trigger-btn {
width: 100%;
}
}

.rs-notification-item-wrapper {
@media screen and (max-width: 450px) {
max-width: 300px;
}
}

utility_colors.scss:

.text-green {
color: #4caf50;
}

.text-blue {
color: #2196f3 ;
}

Dept of Information Technology, SVECW Page 97


OUTING MANAGEMENT

.text-black {
color: #10110f !important;
}

.text-white {
color: #d2d5cc;
}
.text-red {
color: red;
}

.text-black-45 {
// color: rgba(0, 0, 0, 0.45);
color: #d2d5cc;
}

.text-black-70 {
// color: rgba(0, 0, 0, 0.7);
color: #d2d5cc;
}

.border-green {
border: 3px solid rgb(17, 255, 17);
}

.img-b {
border: 3px solid rgb(16, 82, 0);
border-radius: 5px;
}

.bg-black-02 {
background-color: rgba(0, 0, 0, 0.02);
}
.bg-black-01 {
background-color: #22252a;
}
.rs-avatar-image {
position: inherit;
}

.text-wrap {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

Dept of Information Technology, SVECW Page 98


OUTING MANAGEMENT

utility.scss:

$indent_1: 5px;
$indent_2: 10px;
$indent_3: 15px;

.link-unstyled {
&,
&:visited,
&:hover,
&:active,
&:focus,
&:active:hover {
text-decoration: none;
}
}

.text-center {
text-align: center;
}

.text-right {
text-align: right;
}

.text-disappear {
white-space: nowrap !important;
text-overflow: ellipsis !important;
overflow: hidden !important;
}

.overflow-y-scroll {
overflow-y: scroll;
}

.width-250 {
width: 250px;
}

.width-200 {
width: 200px;
Dept of Information Technology, SVECW Page 99
OUTING MANAGEMENT

.height-150 {
height: 150px;
}
.width-150 {
width: 150px;
}
.height-200 {
height: 200px;
}

.height-220 {
height: 220px;
}

.h-100 {
height: 100%;
}

.w-100 {
width: 100%;
}

.mw-100 {
max-width: 100%;
}

.mh-100 {
max-height: 100%;
}

.w-auto {
width: auto;
}

.h-auto {
height: auto;
}

.d-none {
display: none;
}

.d-inline-block {
display: inline-block;
Dept of Information Technology, SVECW Page
100
OUTING MANAGEMENT

.d-block {
display: block;
}

.d-flex {
display: flex;
}

.d-inline-flex {
display: inline-flex;
}

.flex-column {
flex-direction: column;
}

.flex-wrap {
flex-wrap: wrap;
}

.align-items-center {
align-items: center;
}

.justify-content-between {
justify-content: space-between;
}

.justify-content-center {
justify-content: center;
}

.padded {
padding: 10px;
}

.cursor-pointer {
&:hover {
cursor: pointer;
}
}

.ws-nowrap {
white-space: nowrap;
Dept of Information Technology, SVECW Page
101
OUTING MANAGEMENT

.br-circle {
border-radius: 50%;
}

.font-bolder {
font-weight: 500;
}

.font-normal {
font-weight: 400;
}

.italic {
font-style: italic;
}

.word-break-all {
word-break: break-all;
}

.font-huge {
font-size: 100px;
}

.font-small {
font-size: 17px;
}
.contain-scroll {
overscroll-behavior: contain;
}

.mx-auto {
margin-left: auto;
margin-right: auto;
}

.px-0 {
padding-left: 0;
padding-right: 0;
}

.p-0 {
padding: 0;
}
Dept of Information Technology, SVECW Page
102
OUTING MANAGEMENT

.m-0 {
margin: 0;
}

.mt-page {
margin-top: 150px;
}

.mt-1 {
margin-top: $indent_1;
}

.mt-2 {
margin-top: $indent_2;
}

.mt-3 {
margin-top: $indent_3;
}

.mb-1 {
margin-bottom: $indent_1;
}

.mb-2 {
margin-bottom: $indent_2;
}

.mb-3 {
margin-bottom: $indent_3;
}

.ml-1 {
margin-left: $indent_1;
}

.ml-2 {
margin-left: $indent_2;
}

.ml-3 {
margin-left: $indent_3;
}

.mr-1 {
Dept of Information Technology, SVECW Page
103
OUTING MANAGEMENT

margin-right: $indent_1;
}

.mr-2 {
margin-right: $indent_2;
}

.mr-3 {
margin-right: $indent_3;
}

.pt-1 {
padding-top: $indent_1;
}

.pt-2 {
padding-top: $indent_2;
}

.pt-3 {
padding-top: $indent_3;
}

.pb-1 {
padding-bottom: $indent_1;
}

.pb-2 {
padding-bottom: $indent_2;
}

.pl-1 {
padding-left: 0.5rem;
}
.pr-4 {
padding-right: 1rem;
}
.op-color {
color: rgb(141, 141, 141);
opacity: 0.6;
}

.bg-c-grey {
background-color: #17141d;
}

Dept of Information Technology, SVECW Page


104
OUTING MANAGEMENT

App.css:

.App {
text-align: center;
}

.App-logo {
height: 40vmin;
pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {


.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}

.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}

.App-link {
color: #61dafb;
}

@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
Dept of Information Technology, SVECW Page
105
OUTING MANAGEMENT

App.js:

import './styles/main.scss';
import 'rsuite/dist/rsuite.min.css';
import './App.css';
import {BrowserRouter as Router,Routes,Route} from 'react-router-dom';
import PrivateRoute from './components/PrivateRoute';
import PublicRoute from './components/PublicRoute';
import { ProfileContext } from './context/ProfileContext';
import LogIn from './pages/logins/LogIn/LogIn';
import SignUp from './pages/logins/SignUp/SignUp';
import Home from './pages/Home/index';

function App() {

return (
<div>
<Router>
<ProfileContext>
<Routes>
<Route path = "/signin" element = {<PublicRoute />}/>
<Route path = "/" element = {<PrivateRoute />}/>
<Route path = "/login" element = {<LogIn />}/>
<Route path = "/signup" element = {<SignUp />}/>
<Route path = "*" element={<Home />} />
</Routes>
</ProfileContext>
</Router>
</div>
);
}

export default App;

index.js:

import React from 'react';


import ReactDOM from 'react-dom/client';
import App from './App';

Dept of Information Technology, SVECW Page


106
OUTING MANAGEMENT

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

.firebaserc

{
"projects": {
"default": "chatroomhub-5ffa3"
}
}

database.rules.json

{
"rules": {
"profiles": {
"$user_id": {
".read": "$user_id === auth.uid",
".write": "$user_id === auth.uid"
}
},
"rooms": {
".read": "auth !== null",
"$room_id": {
".read": "auth !== null",
".write": "!data.exists() || data.child('admins').child(auth.uid).val() == true",
"lastMessage":{
".write" : "auth !== null"
}
}
},
"messages": {
".read": "auth !== null",
".write": "auth !== null",
".indexOn": ["author/uid", "roomId"],
"$message_id": {
".read": "auth !== null",
".write": "auth !== null"
}
},

Dept of Information Technology, SVECW Page


107
OUTING MANAGEMENT

"status": {
"$user_id": {
".read": "auth !== null",
".write": "$user_id === auth.uid"
}
},
".read": false,
".write": false
}
}

firebase.json

{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "build",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}

Package.json

{
"name": "chatroomhub",
"version": "0.1.0",
"private": true,
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.1",
"@fortawesome/free-solid-svg-icons": "^6.5.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@rsuite/icons": "^1.0.3",

Dept of Information Technology, SVECW Page


108
OUTING MANAGEMENT

"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"cross-env": "^7.0.3",
"file-type": "^19.0.0",
"firebase": "^10.6.0",
"node-sass": "^7.0.3",
"react": "^18.2.0",
"react-avatar-editor": "^13.0.0",
"react-dom": "^18.2.0",
"react-icons": "^4.12.0",
"react-mic": "^12.4.6",
"react-router": "^6.18.0",
"react-router-dom": "^6.20.0",
"react-scripts": "5.0.1",
"react-toastify": "^9.1.3",
"rsuite": "^5.45.0",
"styled-components": "^6.1.1",
"sweetalert2": "^11.10.0",
"timeago-react": "^3.0.6",
"use-context-selector": "^1.4.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint ."
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
Dept of Information Technology, SVECW Page
109
OUTING MANAGEMENT

]
},
"devDependencies": {
"eslint": "^8.55.0"
}
}

Dept of Information Technology, SVECW Page


110

You might also like