0% found this document useful (0 votes)
19 views35 pages

Chat Application API Error Handling

The document summarizes the file structure and key components of a web-based chat application created with React. It describes 6 files in the public directory including the index.html and manifest files. It then describes the src directory containing asset images, and two main component files: ChatContainer.jsx which displays the chat messages and ChatInput.jsx which handles sending new messages. Both components are styled using Styled Components.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views35 pages

Chat Application API Error Handling

The document summarizes the file structure and key components of a web-based chat application created with React. It describes 6 files in the public directory including the index.html and manifest files. It then describes the src directory containing asset images, and two main component files: ChatContainer.jsx which displays the chat messages and ChatInput.jsx which handles sending new messages. Both components are styled using Styled Components.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

WEB- BASED CHAT APPLICATION USING REACT

Created by-
Sachin Kumar
Sachingpt771@[Link]

In Public (Frontend)-
The files and codes are --

Public-

In public we have 6 directory when we create our react app these files included --

1).[Link]

2).[Link]

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/[Link]" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/[Link]" />
<!--
[Link] provides metadata used when your web app is installed on a
user's mobile device or desktop. See [Link]
-->
<link rel="manifest" href="%PUBLIC_URL%/[Link]" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.

Unlike "/[Link]" or "[Link]", "%PUBLIC_URL%/[Link]" will


work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.

You can add webfonts, meta tags, or analytics to this file.


The build step will place the bundled scripts into the <body> tag.

To begin the development, run `npm start` or `yarn start`.


To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

3). [Link]

4).[Link]
5).[Link]---
Necessary file install in this directory.

6).[Link]

Src directory-
1). Assets-
 [Link]
 [Link]

 [Link]
2).Components-
 [Link]
import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components";
import ChatInput from "./ChatInput";
import Logout from "./Logout";
import { v4 as uuidv4 } from "uuid";
import axios from "axios";
import { sendMessageRoute, recieveMessageRoute } from "../utils/APIRoutes";

export default function ChatContainer({ currentChat, socket }) {


const [messages, setMessages] = useState([]);
const scrollRef = useRef();
const [arrivalMessage, setArrivalMessage] = useState(null);

useEffect(async () => {
const data = await [Link](
[Link]([Link].REACT_APP_LOCALHOST_KEY)
);
const response = await [Link](recieveMessageRoute, {
from: data._id,
to: currentChat._id,
});
setMessages([Link]);
}, [currentChat]);

useEffect(() => {
const getCurrentChat = async () => {
if (currentChat) {
await [Link](
[Link]([Link].REACT_APP_LOCALHOST_KEY)
)._id;
}
};
getCurrentChat();
}, [currentChat]);

const handleSendMsg = async (msg) => {


const data = await [Link](
[Link]([Link].REACT_APP_LOCALHOST_KEY)
);
[Link]("send-msg", {
to: currentChat._id,
from: data._id,
msg,
});
await [Link](sendMessageRoute, {
from: data._id,
to: currentChat._id,
message: msg,
});

const msgs = [...messages];


[Link]({ fromSelf: true, message: msg });
setMessages(msgs);
};

useEffect(() => {
if ([Link]) {
[Link]("msg-recieve", (msg) => {
setArrivalMessage({ fromSelf: false, message: msg });
});
}
}, []);

useEffect(() => {
arrivalMessage && setMessages((prev) => [...prev, arrivalMessage]);
}, [arrivalMessage]);

useEffect(() => {
[Link]?.scrollIntoView({ behavior: "smooth" });
}, [messages]);

return (
<Container>
<div className="chat-header">
<div className="user-details">
<div className="avatar">
<img
src={`data:image/svg+xml;base64,${[Link]}`}
alt=""
/>
</div>
<div className="username">
<h3>{[Link]}</h3>
</div>
</div>
<Logout />
</div>
<div className="chat-messages">
{[Link]((message) => {
return (
<div ref={scrollRef} key={uuidv4()}>
<div
className={`message ${
[Link] ? "sended" : "recieved"
}`}
>
<div className="content ">
<p>{[Link]}</p>
</div>
</div>
</div>
);
})}
</div>
<ChatInput handleSendMsg={handleSendMsg} />
</Container>
);
}

const Container = [Link]`


display: grid;
grid-template-rows: 10% 80% 10%;
gap: 0.1rem;
overflow: hidden;
@media screen and (min-width: 720px) and (max-width: 1080px) {
grid-template-rows: 15% 70% 15%;
}
.chat-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 2rem;
.user-details {
display: flex;
align-items: center;
gap: 1rem;
.avatar {
img {
height: 3rem;
}
}
.username {
h3 {
color: white;
}
}
}
}
.chat-messages {
padding: 1rem 2rem;
display: flex;
flex-direction: column;
gap: 1rem;
overflow: auto;
&::-webkit-scrollbar {
width: 0.2rem;
&-thumb {
background-color: #ffffff39;
width: 0.1rem;
border-radius: 1rem;
}
}
.message {
display: flex;
align-items: center;
.content {
max-width: 40%;
overflow-wrap: break-word;
padding: 1rem;
font-size: 1.1rem;
border-radius: 1rem;
color: #d1d1d1;
@media screen and (min-width: 720px) and (max-width: 1080px) {
max-width: 70%;
}
}
}
.sended {
justify-content: flex-end;
.content {
background-color: #4f04ff21;
}
}
.recieved {
justify-content: flex-start;
.content {
background-color: #9900ff20;
}
}
}
`;

 [Link]
import React, { useState } from "react";
import { BsEmojiSmileFill } from "react-icons/bs";
import { IoMdSend } from "react-icons/io";
import styled from "styled-components";
import Picker from "emoji-picker-react";

export default function ChatInput({ handleSendMsg }) {


const [msg, setMsg] = useState("");
const [showEmojiPicker, setShowEmojiPicker] = useState(false);
const handleEmojiPickerhideShow = () => {
setShowEmojiPicker(!showEmojiPicker);
};
const handleEmojiClick = (event, emojiObject) => {
let message = msg;
message += [Link];
setMsg(message);
};

const sendChat = (event) => {


[Link]();
if ([Link] > 0) {
handleSendMsg(msg);
setMsg("");
}
};

return (
<Container>
<div className="button-container">
<div className="emoji">
<BsEmojiSmileFill onClick={handleEmojiPickerhideShow} />
{showEmojiPicker && <Picker onEmojiClick={handleEmojiClick} />}
</div>
</div>
<form className="input-container" onSubmit={(event) => sendChat(event)}>
<input
type="text"
placeholder="type your message here"
onChange={(e) => setMsg([Link])}
value={msg}
/>
<button type="submit">
<IoMdSend />
</button>
</form>
</Container>
);
}

const Container = [Link]`


display: grid;
align-items: center;
grid-template-columns: 5% 95%;
background-color: #080420;
padding: 0 2rem;
@media screen and (min-width: 720px) and (max-width: 1080px) {
padding: 0 1rem;
gap: 1rem;
}
.button-container {
display: flex;
align-items: center;
color: white;
gap: 1rem;
.emoji {
position: relative;
svg {
font-size: 1.5rem;
color: #ffff00c8;
cursor: pointer;
}
.emoji-picker-react {
position: absolute;
top: -350px;
background-color: #080420;
box-shadow: 0 5px 10px #9a86f3;
border-color: #9a86f3;
.emoji-scroll-wrapper::-webkit-scrollbar {
background-color: #080420;
width: 5px;
&-thumb {
background-color: #9a86f3;
}
}
.emoji-categories {
button {
filter: contrast(0);
}
}
.emoji-search {
background-color: transparent;
border-color: #9a86f3;
}
.emoji-group:before {
background-color: #080420;
}
}
}
}
.input-container {
width: 100%;
border-radius: 2rem;
display: flex;
align-items: center;
gap: 2rem;
background-color: #ffffff34;
input {
width: 90%;
height: 60%;
background-color: transparent;
color: white;
border: none;
padding-left: 1rem;
font-size: 1.2rem;

&::selection {
background-color: #9a86f3;
}
&:focus {
outline: none;
}
}
button {
padding: 0.3rem 2rem;
border-radius: 2rem;
display: flex;
justify-content: center;
align-items: center;
background-color: #9a86f3;
border: none;
@media screen and (min-width: 720px) and (max-width: 1080px) {
padding: 0.3rem 1rem;
svg {
font-size: 1rem;
}
}
svg {
font-size: 2rem;
color: white;
}
}
}
`;

 [Link]
import React, { useState, useEffect } from "react";
import styled from "styled-components";
import Logo from "../assets/[Link]";

export default function Contacts({ contacts, changeChat }) {


const [currentUserName, setCurrentUserName] = useState(undefined);
const [currentUserImage, setCurrentUserImage] = useState(undefined);
const [currentSelected, setCurrentSelected] = useState(undefined);
useEffect(async () => {
const data = await [Link](
[Link]([Link].REACT_APP_LOCALHOST_KEY)
);
setCurrentUserName([Link]);
setCurrentUserImage([Link]);
}, []);
const changeCurrentChat = (index, contact) => {
setCurrentSelected(index);
changeChat(contact);
};
return (
<>
{currentUserImage && currentUserImage && (
<Container>
<div className="brand">
<img src={Logo} alt="logo" />
<h3>snappy</h3>
</div>
<div className="contacts">
{[Link]((contact, index) => {
return (
<div
key={contact._id}
className={`contact ${
index === currentSelected ? "selected" : ""
}`}
onClick={() => changeCurrentChat(index, contact)}
>
<div className="avatar">
<img
src={`data:image/svg+xml;base64,${[Link]}`}
alt=""
/>
</div>
<div className="username">
<h3>{[Link]}</h3>
</div>
</div>
);
})}
</div>
<div className="current-user">
<div className="avatar">
<img
src={`data:image/svg+xml;base64,${currentUserImage}`}
alt="avatar"
/>
</div>
<div className="username">
<h2>{currentUserName}</h2>
</div>
</div>
</Container>
)}
</>
);
}
const Container = [Link]`
display: grid;
grid-template-rows: 10% 75% 15%;
overflow: hidden;
background-color: #080420;
.brand {
display: flex;
align-items: center;
gap: 1rem;
justify-content: center;
img {
height: 2rem;
}
h3 {
color: white;
text-transform: uppercase;
}
}
.contacts {
display: flex;
flex-direction: column;
align-items: center;
overflow: auto;
gap: 0.8rem;
&::-webkit-scrollbar {
width: 0.2rem;
&-thumb {
background-color: #ffffff39;
width: 0.1rem;
border-radius: 1rem;
}
}
.contact {
background-color: #ffffff34;
min-height: 5rem;
cursor: pointer;
width: 90%;
border-radius: 0.2rem;
padding: 0.4rem;
display: flex;
gap: 1rem;
align-items: center;
transition: 0.5s ease-in-out;
.avatar {
img {
height: 3rem;
}
}
.username {
h3 {
color: white;
}
}
}
.selected {
background-color: #9a86f3;
}
}

.current-user {
background-color: #0d0d30;
display: flex;
justify-content: center;
align-items: center;
gap: 2rem;
.avatar {
img {
height: 4rem;
max-inline-size: 100%;
}
}
.username {
h2 {
color: white;
}
}
@media screen and (min-width: 720px) and (max-width: 1080px) {
gap: 0.5rem;
.username {
h2 {
font-size: 1rem;
}
}
}
}
`;

 [Link]-

import React from "react";


import { useNavigate } from "react-router-dom";
import { BiPowerOff } from "react-icons/bi";
import styled from "styled-components";
import axios from "axios";
import { logoutRoute } from "../utils/APIRoutes";
export default function Logout() {
const navigate = useNavigate();
const handleClick = async () => {
const id = await [Link](
[Link]([Link].REACT_APP_LOCALHOST_KEY)
)._id;
const data = await [Link](`${logoutRoute}/${id}`);
if ([Link] === 200) {
[Link]();
navigate("/login");
}
};
return (
<Button onClick={handleClick}>
<BiPowerOff />
</Button>
);
}

const Button = [Link]`


display: flex;
justify-content: center;
align-items: center;
padding: 0.5rem;
border-radius: 0.5rem;
background-color: #9a86f3;
border: none;
cursor: pointer;
svg {
font-size: 1.3rem;
color: #ebe7ff;
}
`;

 [Link]
import React, { useEffect, useState } from "react";
import styled from "styled-components";
import axios from "axios";
import { Buffer } from "buffer";
import loader from "../assets/[Link]";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/[Link]";
import { useNavigate } from "react-router-dom";
import { setAvatarRoute } from "../utils/APIRoutes";
export default function SetAvatar() {
const api = `[Link]
const navigate = useNavigate();
const [avatars, setAvatars] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [selectedAvatar, setSelectedAvatar] = useState(undefined);
const toastOptions = {
position: "bottom-right",
autoClose: 8000,
pauseOnHover: true,
draggable: true,
theme: "dark",
};

useEffect(async () => {
if (![Link]([Link].REACT_APP_LOCALHOST_KEY))
navigate("/login");
}, []);

const setProfilePicture = async () => {


if (selectedAvatar === undefined) {
[Link]("Please select an avatar", toastOptions);
} else {
const user = await [Link](
[Link]([Link].REACT_APP_LOCALHOST_KEY)
);

const { data } = await [Link](`${setAvatarRoute}/${user._id}`, {


image: avatars[selectedAvatar],
});

if ([Link]) {
[Link] = true;
[Link] = [Link];
[Link](
[Link].REACT_APP_LOCALHOST_KEY,
[Link](user)
);
navigate("/");
} else {
[Link]("Error setting avatar. Please try again.", toastOptions);
}
}
};

useEffect(async () => {
const data = [];
for (let i = 0; i < 4; i++) {
const image = await [Link](
`${api}/${[Link]([Link]() * 1000)}`
);
const buffer = new Buffer([Link]);
[Link]([Link]("base64"));
}
setAvatars(data);
setIsLoading(false);
}, []);
return (
<>
{isLoading ? (
<Container>
<img src={loader} alt="loader" className="loader" />
</Container>
):(
<Container>
<div className="title-container">
<h1>Pick an Avatar as your profile picture</h1>
</div>
<div className="avatars">
{[Link]((avatar, index) => {
return (
<div
className={`avatar ${
selectedAvatar === index ? "selected" : ""
}`}
>
<img
src={`data:image/svg+xml;base64,${avatar}`}
alt="avatar"
key={avatar}
onClick={() => setSelectedAvatar(index)}
/>
</div>
);
})}
</div>
<button onClick={setProfilePicture} className="submit-btn">
Set as Profile Picture
</button>
<ToastContainer />
</Container>
)}
</>
);
}

const Container = [Link]`


display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 3rem;
background-color: #131324;
height: 100vh;
width: 100vw;

.loader {
max-inline-size: 100%;
}

.title-container {
h1 {
color: white;
}
}
.avatars {
display: flex;
gap: 2rem;

.avatar {
border: 0.4rem solid transparent;
padding: 0.4rem;
border-radius: 5rem;
display: flex;
justify-content: center;
align-items: center;
transition: 0.5s ease-in-out;
img {
height: 6rem;
transition: 0.5s ease-in-out;
}
}
.selected {
border: 0.4rem solid #4e0eff;
}
}
.submit-btn {
background-color: #4e0eff;
color: white;
padding: 1rem 2rem;
border: none;
font-weight: bold;
cursor: pointer;
border-radius: 0.4rem;
font-size: 1rem;
text-transform: uppercase;
&:hover {
background-color: #4e0eff;
}
}
`;

 [Link]
import React, { useState, useEffect } from "react";
import styled from "styled-components";
import Robot from "../assets/[Link]";
export default function Welcome() {
const [userName, setUserName] = useState("");
useEffect(async () => {
setUserName(
await [Link](
[Link]([Link].REACT_APP_LOCALHOST_KEY)
).username
);
}, []);
return (
<Container>
<img src={Robot} alt="" />
<h1>
Welcome, <span>{userName}!</span>
</h1>
<h3>Please select a chat to Start messaging.</h3>
</Container>
);
}

const Container = [Link]`


display: flex;
justify-content: center;
align-items: center;
color: white;
flex-direction: column;
img {
height: 20rem;
}
span {
color: #4e0eff;
}
`;

Pages Directory---

[Link]-

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


import axios from "axios";
import { useNavigate } from "react-router-dom";
import { io } from "[Link]-client";
import styled from "styled-components";
import { allUsersRoute, host } from "../utils/APIRoutes";
import ChatContainer from "../components/ChatContainer";
import Contacts from "../components/Contacts";
import Welcome from "../components/Welcome";

export default function Chat() {


const navigate = useNavigate();
const socket = useRef();
const [contacts, setContacts] = useState([]);
const [currentChat, setCurrentChat] = useState(undefined);
const [currentUser, setCurrentUser] = useState(undefined);
useEffect(async () => {
if (![Link]([Link].REACT_APP_LOCALHOST_KEY)) {
navigate("/login");
} else {
setCurrentUser(
await [Link](
[Link]([Link].REACT_APP_LOCALHOST_KEY)
)
);
}
}, []);
useEffect(() => {
if (currentUser) {
[Link] = io(host);
[Link]("add-user", currentUser._id);
}
}, [currentUser]);
useEffect(async () => {
if (currentUser) {
if ([Link]) {
const data = await [Link](`${allUsersRoute}/${currentUser._id}`);
setContacts([Link]);
} else {
navigate("/setAvatar");
}
}
}, [currentUser]);
const handleChatChange = (chat) => {
setCurrentChat(chat);
};
return (
<>
<Container>
<div className="container">
<Contacts contacts={contacts} changeChat={handleChatChange} />
{currentChat === undefined ? (
<Welcome />
):(
<ChatContainer currentChat={currentChat} socket={socket} />
)}
</div>
</Container>
</>
);
}

const Container = [Link]`


height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
justify-content: center;
gap: 1rem;
align-items: center;
background-color: #131324;
.container {
height: 85vh;
width: 85vw;
background-color: #00000076;
display: grid;
grid-template-columns: 25% 75%;
@media screen and (min-width: 720px) and (max-width: 1080px) {
grid-template-columns: 35% 65%;
}
}
`;

[Link]

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


import axios from "axios";
import styled from "styled-components";
import { useNavigate, Link } from "react-router-dom";
import Logo from "../assets/[Link]";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/[Link]";
import { loginRoute } from "../utils/APIRoutes";

export default function Login() {


const navigate = useNavigate();
const [values, setValues] = useState({ username: "", password: "" });
const toastOptions = {
position: "bottom-right",
autoClose: 8000,
pauseOnHover: true,
draggable: true,
theme: "dark",
};
useEffect(() => {
if ([Link]([Link].REACT_APP_LOCALHOST_KEY)) {
navigate("/");
}
}, []);

const handleChange = (event) => {


setValues({ ...values, [[Link]]: [Link] });
};

const validateForm = () => {


const { username, password } = values;
if (username === "") {
[Link]("Email and Password is required.", toastOptions);
return false;
} else if (password === "") {
[Link]("Email and Password is required.", toastOptions);
return false;
}
return true;
};

const handleSubmit = async (event) => {


[Link]();
if (validateForm()) {
const { username, password } = values;
const { data } = await [Link](loginRoute, {
username,
password,
});
if ([Link] === false) {
[Link]([Link], toastOptions);
}
if ([Link] === true) {
[Link](
[Link].REACT_APP_LOCALHOST_KEY,
[Link]([Link])
);

navigate("/");
}
}
};

return (
<>
<FormContainer>
<form action="" onSubmit={(event) => handleSubmit(event)}>
<div className="brand">
<img src={Logo} alt="logo" />
<h1>snappy</h1>
</div>
<input
type="text"
placeholder="Username"
name="username"
onChange={(e) => handleChange(e)}
min="3"
/>
<input
type="password"
placeholder="Password"
name="password"
onChange={(e) => handleChange(e)}
/>
<button type="submit">Log In</button>
<span>
Don't have an account ? <Link to="/register">Create One.</Link>
</span>
</form>
</FormContainer>
<ToastContainer />
</>
);
}

const FormContainer = [Link]`


height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
justify-content: center;
gap: 1rem;
align-items: center;
background-color: #131324;
.brand {
display: flex;
align-items: center;
gap: 1rem;
justify-content: center;
img {
height: 5rem;
}
h1 {
color: white;
text-transform: uppercase;
}
}
form {
display: flex;
flex-direction: column;
gap: 2rem;
background-color: #00000076;
border-radius: 2rem;
padding: 5rem;
}
input {
background-color: transparent;
padding: 1rem;
border: 0.1rem solid #4e0eff;
border-radius: 0.4rem;
color: white;
width: 100%;
font-size: 1rem;
&:focus {
border: 0.1rem solid #997af0;
outline: none;
}
}
button {
background-color: #4e0eff;
color: white;
padding: 1rem 2rem;
border: none;
font-weight: bold;
cursor: pointer;
border-radius: 0.4rem;
font-size: 1rem;
text-transform: uppercase;
&:hover {
background-color: #4e0eff;
}
}
span {
color: white;
text-transform: uppercase;
a{
color: #4e0eff;
text-decoration: none;
font-weight: bold;
}
}
`;

[Link]-
import React, { useState, useEffect } from "react";
import axios from "axios";
import styled from "styled-components";
import { useNavigate, Link } from "react-router-dom";
import Logo from "../assets/[Link]";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/[Link]";
import { registerRoute } from "../utils/APIRoutes";

export default function Register() {


const navigate = useNavigate();
const toastOptions = {
position: "bottom-right",
autoClose: 8000,
pauseOnHover: true,
draggable: true,
theme: "dark",
};
const [values, setValues] = useState({
username: "",
email: "",
password: "",
confirmPassword: "",
});

useEffect(() => {
if ([Link]([Link].REACT_APP_LOCALHOST_KEY)) {
navigate("/");
}
}, []);

const handleChange = (event) => {


setValues({ ...values, [[Link]]: [Link] });
};

const handleValidation = () => {


const { password, confirmPassword, username, email } = values;
if (password !== confirmPassword) {
[Link](
"Password and confirm password should be same.",
toastOptions
);
return false;
} else if ([Link] < 3) {
[Link](
"Username should be greater than 3 characters.",
toastOptions
);
return false;
} else if ([Link] < 8) {
[Link](
"Password should be equal or greater than 8 characters.",
toastOptions
);
return false;
} else if (email === "") {
[Link]("Email is required.", toastOptions);
return false;
}

return true;
};

const handleSubmit = async (event) => {


[Link]();
if (handleValidation()) {
const { email, username, password } = values;
const { data } = await [Link](registerRoute, {
username,
email,
password,
});

if ([Link] === false) {


[Link]([Link], toastOptions);
}
if ([Link] === true) {
[Link](
[Link].REACT_APP_LOCALHOST_KEY,
[Link]([Link])
);
navigate("/");
}
}
};

return (
<>
<FormContainer>
<form action="" onSubmit={(event) => handleSubmit(event)}>
<div className="brand">
<img src={Logo} alt="logo" />
<h1>snappy</h1>
</div>
<input
type="text"
placeholder="Username"
name="username"
onChange={(e) => handleChange(e)}
/>
<input
type="email"
placeholder="Email"
name="email"
onChange={(e) => handleChange(e)}
/>
<input
type="password"
placeholder="Password"
name="password"
onChange={(e) => handleChange(e)}
/>
<input
type="password"
placeholder="Confirm Password"
name="confirmPassword"
onChange={(e) => handleChange(e)}
/>
<button type="submit">Create User</button>
<span>
Already have an account ? <Link to="/login">Login.</Link>
</span>
</form>
</FormContainer>
<ToastContainer />
</>
);
}

const FormContainer = [Link]`


height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
justify-content: center;
gap: 1rem;
align-items: center;
background-color: #131324;
.brand {
display: flex;
align-items: center;
gap: 1rem;
justify-content: center;
img {
height: 5rem;
}
h1 {
color: white;
text-transform: uppercase;
}
}

form {
display: flex;
flex-direction: column;
gap: 2rem;
background-color: #00000076;
border-radius: 2rem;
padding: 3rem 5rem;
}
input {
background-color: transparent;
padding: 1rem;
border: 0.1rem solid #4e0eff;
border-radius: 0.4rem;
color: white;
width: 100%;
font-size: 1rem;
&:focus {
border: 0.1rem solid #997af0;
outline: none;
}
}
button {
background-color: #4e0eff;
color: white;
padding: 1rem 2rem;
border: none;
font-weight: bold;
cursor: pointer;
border-radius: 0.4rem;
font-size: 1rem;
text-transform: uppercase;
&:hover {
background-color: #4e0eff;
}
}
span {
color: white;
text-transform: uppercase;
a{
color: #4e0eff;
text-decoration: none;
font-weight: bold;
}
}
`;

Utils Directory

 [Link]

export const host = "[Link]


export const loginRoute = `${host}/api/auth/login`;
export const registerRoute = `${host}/api/auth/register`;
export const logoutRoute = `${host}/api/auth/logout`;
export const allUsersRoute = `${host}/api/auth/allusers`;
export const sendMessageRoute = `${host}/api/messages/addmsg`;
export const recieveMessageRoute = `${host}/api/messages/getmsg`;
export const setAvatarRoute = `${host}/api/auth/setavatar`;

[Link] File---

import React from "react";


import { BrowserRouter, Routes, Route } from "react-router-dom";
import SetAvatar from "./components/SetAvatar";
import Chat from "./pages/Chat";
import Login from "./pages/Login";
import Register from "./pages/Register";
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/register" element={<Register />} />
<Route path="/login" element={<Login />} />
<Route path="/setAvatar" element={<SetAvatar />} />
<Route path="/" element={<Chat />} />
</Routes>
</BrowserRouter>
);
}
[Link] File--

@import url("[Link]
family=Josefin+Sans:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,6
00;1,700&display=swap");

*{
margin: 0;
padding: 0;
box-sizing: border-box;
}

body,
button,
input {
font-family: "Josefin Sans", sans-serif;
}

body {
max-height: 100vh;
max-width: 100vw;
overflow: hidden;
}

.Toastify__toast-theme--dark {
background-color: #00000076 !important;
}

[Link] File---

import React from "react";


import ReactDOM from "react-dom";
import App from "./App";
import "./[Link]";
[Link](
<[Link]>
<App />
</[Link]>,
[Link]("root")
);
Backened file(Server)---

1).Controllers—

 [Link]
const Messages = require("../models/messageModel");

[Link] = async (req, res, next) => {


try {
const { from, to } = [Link];

const messages = await [Link]({


users: {
$all: [from, to],
},
}).sort({ updatedAt: 1 });
const projectedMessages = [Link]((msg) => {
return {
fromSelf: [Link]() === from,
message: [Link],
};
});
[Link](projectedMessages);
} catch (ex) {
next(ex);
}
};

[Link] = async (req, res, next) => {


try {
const { from, to, message } = [Link];
const data = await [Link]({
message: { text: message },
users: [from, to],
sender: from,
});

if (data) return [Link]({ msg: "Message added successfully." });


else return [Link]({ msg: "Failed to add message to the database" });
} catch (ex) {
next(ex);
}
};
 [Link]
const User = require("../models/userModel");
const bcrypt = require("bcrypt");

[Link] = async (req, res, next) => {


try {
const { username, password } = [Link];
const user = await [Link]({ username });
if (!user)
return [Link]({ msg: "Incorrect Username or Password", status: false });
const isPasswordValid = await [Link](password, [Link]);
if (!isPasswordValid)
return [Link]({ msg: "Incorrect Username or Password", status: false });
delete [Link];
return [Link]({ status: true, user });
} catch (ex) {
next(ex);
}
};

[Link] = async (req, res, next) => {


try {
const { username, email, password } = [Link];
const usernameCheck = await [Link]({ username });
if (usernameCheck)
return [Link]({ msg: "Username already used", status: false });
const emailCheck = await [Link]({ email });
if (emailCheck)
return [Link]({ msg: "Email already used", status: false });
const hashedPassword = await [Link](password, 10);
const user = await [Link]({
email,
username,
password: hashedPassword,
});
delete [Link];
return [Link]({ status: true, user });
} catch (ex) {
next(ex);
}
};

[Link] = async (req, res, next) => {


try {
const users = await [Link]({ _id: { $ne: [Link] } }).select([
"email",
"username",
"avatarImage",
"_id",
]);
return [Link](users);
} catch (ex) {
next(ex);
}
};

[Link] = async (req, res, next) => {


try {
const userId = [Link];
const avatarImage = [Link];
const userData = await [Link](
userId,
{
isAvatarImageSet: true,
avatarImage,
},
{ new: true }
);
return [Link]({
isSet: [Link],
image: [Link],
});
} catch (ex) {
next(ex);
}
};

[Link] = (req, res, next) => {


try {
if (![Link]) return [Link]({ msg: "User id is required " });
[Link]([Link]);
return [Link](200).send();
} catch (ex) {
next(ex);
}
};

2).models

 [Link] -
const mongoose = require("mongoose");

const MessageSchema = [Link](


{
message: {
text: { type: String, required: true },
},
users: Array,
sender: {
type: [Link],
ref: "User",
required: true,
},
},
{
timestamps: true,
}
);

[Link] = [Link]("Messages", MessageSchema);

 [Link]-

const mongoose = require("mongoose");

const userSchema = new [Link]({


username: {
type: String,
required: true,
min: 3,
max: 20,
unique: true,
},
email: {
type: String,
required: true,
unique: true,
max: 50,
},
password: {
type: String,
required: true,
min: 8,
},
isAvatarImageSet: {
type: Boolean,
default: false,
},
avatarImage: {
type: String,
default: "",
},
});

[Link] = [Link]("Users", userSchema);

3). Routes-

 [Link]
const {
login,
register,
getAllUsers,
setAvatar,
logOut,
} = require("../controllers/userController");

const router = require("express").Router();

[Link]("/login", login);
[Link]("/register", register);
[Link]("/allusers/:id", getAllUsers);
[Link]("/setavatar/:id", setAvatar);
[Link]("/logout/:id", logOut);

[Link] = router;

 [Link]—

const { addMessage, getMessages } = require("../controllers/messageController");


const router = require("express").Router();

[Link]("/addmsg/", addMessage);
[Link]("/getmsg/", getMessages);

[Link] = router;

4). .env file

PORT=5000
MONGO_URL="mongodb://localhost:27017/chat"

5).[Link]

const express = require("express");


const cors = require("cors");
const mongoose = require("mongoose");
const authRoutes = require("./routes/auth");
const messageRoutes = require("./routes/messages");
const app = express();
const socket = require("[Link]");
require("dotenv").config();

[Link](cors());
[Link]([Link]());

mongoose
.connect([Link].MONGO_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
[Link]("DB Connetion Successfull");
})
.catch((err) => {
[Link]([Link]);
});

[Link]("/api/auth", authRoutes);
[Link]("/api/messages", messageRoutes);

const server = [Link]([Link], () =>


[Link](`Server started on ${[Link]}`)
);
const io = socket(server, {
cors: {
origin: "[Link]
credentials: true,
},
});

[Link] = new Map();


[Link]("connection", (socket) => {
[Link] = socket;
[Link]("add-user", (userId) => {
[Link](userId, [Link]);
});

[Link]("send-msg", (data) => {


const sendUserSocket = [Link]([Link]);
if (sendUserSocket) {
[Link](sendUserSocket).emit("msg-recieve", [Link]);
}
});
});

6). [Link]—

{
"name": "chat-app-backend",
"version": "1.0.0",
"description": "",
"main": "[Link]",
"scripts": {
"start": "nodemon [Link]",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.0.1",
"cors": "^2.8.5",
"dotenv": "^16.0.0",
"express": "^4.17.2",
"mongoose": "^6.2.1",
"nodemon": "^2.0.15",
"[Link]": "^4.4.1"
}
}

7). Yarn lock---

When you install many tool for it . It’s file should be save in that area. Like—[Link],express,axios ,mongoose etc
many more.
Output :-

Login page and Create your Id-

Chat Page-
## We can logout by RightSide upper button.
Electronic copy available at: [Link]

Common questions

Powered by AI

Client-side routing will navigate users to the login page if no user data is found in 'localStorage'. If the current user is authenticated but their avatar image is not set ('isAvatarImageSet' is false), they are routed to the avatar setting page to ensure they complete the profile setup .

The application employs Socket.IO for real-time messaging. On the server side, a socket connection is established where users are added to an 'onlineUsers' map when they connect. Whenever a message is sent, the server looks up the recipient in the map and, if found, emits the message to the recipient's socket connection .

The SetAvatar component uses the 'useEffect' hook to check if the user information is stored in 'localStorage' under the key 'REACT_APP_LOCALHOST_KEY'. If no such data exists, it automatically navigates the user to the login page using the 'useNavigate' hook .

To register a new user, the backend checks if the username and email are unique. Once validated, bcrypt is used to hash the user's password before storing it in the database, ensuring password security. The password field is excluded from the response to maintain confidentiality .

The application differentiates between users by checking the 'isAvatarImageSet' attribute from the user’s data. If this attribute is true, it confirms that the user has set an avatar. If false, the user is redirected to the Avatar Setting page until they complete the avatar selection process .

The application employs CSS media queries within styled-components to adjust padding, font sizes, and layout based on the screen width. This ensures that components such as buttons, avatars, and containers reflow gracefully across devices with screen widths between 720px and 1080px .

The 'Messages' mongoose model defines the schema for storing chat messages in the database. It specifies a message object containing the text field, an array of user IDs representing the conversation participants, and a sender ID as a foreign key reference to the 'User' model. The schema includes timestamps for tracking when messages are created or updated .

The 'Welcome' component uses the 'useEffect' hook to retrieve user data stored in 'localStorage' under the key 'REACT_APP_LOCALHOST_KEY'. It then parses this data to obtain the username, which is subsequently set to the 'userName' state variable. This value is then displayed within a greeting message on the component .

The application uses 'styled-components', a CSS-in-JS library, to style React components. This approach allows for CSS to be written directly within JavaScript using tagged template literals, providing scoped styles that are automatically applied to specified components without affecting the global styles .

During the login process, the backend checks the user credentials by finding the user in the database based on the provided username. If a user is found, the bcrypt library is used to compare the provided password with the stored hashed password. If the comparison is successful, the user is considered authenticated. The password is removed from the user object before returning a successful response .

You might also like