A real time Web-App for one to one chatting.

Overview

We-Vibe

A real time web-app for one to one chatting. The project is broadly divided into two parts - Server and Public (client).
The Socket.io module has been used for bi-directional and low latency communication

Tech Stack Used

MERN

Hosting Platform

The Web-App (used Netlify): https://wevibe.netlify.app/
The Server (Used Heroku): https://wevibe-backend.herokuapp.com/

Ther Server is mainly used for handling the HTTP requests and accesing the mongoDB database hosted on mongoDB Atlas.

THE UI

Login Page

image

Registration Page

image

Toasts

react-toastify have been used for the purposes of notifying the users.

image

Avatar Image

Upon Registration, the User is Prompted to set an Avatar Image out of four random avatars.
These random avatars are fetched from https://api.multiavatar.com/4645646

image

Welcome Page

image

The Chat

image image
import Picker from "emoji-picker-react" for implementing the emoji's Input.

The App and Server

Mongoose Models

Two Mongoose Models have been used - userModel & messageModel

  • The userModel stores the basic user details like username email password isAvatarImageSet avatarImage
  • The messageModel contains the message users sender

The userSchema

const userSchema = new mongoose.Schema({
  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: "",
  },
});

The messageSchema

const MessageSchema = mongoose.Schema(
  {
    message: {
      text: { type: String, required: true },
    },
    users: Array,
    sender: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
  },
  {
    timestamps: true,
  }
);

User Registration and Login

The input changes in the login/regsitartion forms are continuously tracked using {useState} from "react" On submitting, the handleSubmit functions for the respective action (login/register) are called using the onSubmit attribute.

  <form action="" onSubmit={(event) => handleSubmit(event)}>
  • handleSubmit for Login

    const handleSubmit = async (event) => {
      event.preventDefault();
      if (validateForm()) {
        const { username, password } = values;
        const { data } = await axios.post(loginRoute, {
          username,
          password,
        });
        if (data.status === false) {
          toast.error(data.msg, toastOptions);
        }
        if (data.status === true) {
          localStorage.setItem(
            process.env.REACT_APP_LOCALHOST_KEY,
            JSON.stringify(data.user)
          );
          navigate("/");
        }
      }
    };
  • handleSubmit for Registration

    const handleSubmit = async (event) => {
      event.preventDefault();
      if (handleValidation()) {
        const { email, username, password } = values;
        const { data } = await axios.post(registerRoute, {
          username,
          email,
          password,
        });
        // console.log(data);
        if (data.status === false) {
          toast.error(data.msg, toastOptions);
        }
        if (data.status === true) {
          localStorage.setItem(
            process.env.REACT_APP_LOCALHOST_KEY,
            JSON.stringify(data.user)
          );
          navigate("/");
        }
      }
    };

axios.post() is used for the HTTP post request through which the data is passed on to the backend server where the login and regsiter APIs are implemented.
The backend server uses bcrypt which hashes and salts the password, before we store it in our database.

  • Register API

      module.exports.register = async (req, res, next) => {
        try {
          const { username, email, password } = req.body;
          const usernameCheck = await User.findOne({ username });
          if (usernameCheck)
            return res.json({ msg: "Username already used", status: false });
          const emailCheck = await User.findOne({ email });
          if (emailCheck)
            return res.json({ msg: "Email already used", status: false });
          const hashedPassword = await bcrypt.hash(password, 10);
          const user = await User.create({
            email,
            username,
            password: hashedPassword,
          });
          delete user.password;
          return res.json({ status: true, user });
        } catch (ex) {
          next(ex);
        }
      };
    • req.body is destructured into username email password.
    • First we check if the user already exists in our database, if so we toast an error with a message Username already used or Email already used depending on the scenario.
    • If they don't, the password (user input) undergoes hashing and ten rounds of salting. Hashing and salting exponentially increases the security level, and makes it impossible to decrypt this encrypted password.
    • This hashed password is now stored in our database alongside username and email.
  • Login API

      module.exports.login = async (req, res, next) => {
        try {
          const { username, password } = req.body;
          const user = await User.findOne({ username });
          if (!user)
            return res.json({ msg: "Incorrect Username or Password", status: false });
          const isPasswordValid = await bcrypt.compare(password, user.password);
          if (!isPasswordValid)
            return res.json({ msg: "Incorrect Username or Password", status: false });
          delete user.password;
          return res.json({ status: true, user });
        } catch (ex) {
          next(ex);
        }
      };
    • req.body is destructured into username password.
    • First we find the username in our database, if no user found, toast an error with a message Incorrect Username or Password.
    • If found, we compare the user input password with the hashed password stored against the input username using bcrypt.compare() which return a boolean.
    • If evaluated to false, toast an error with the message Incorrect Username or Password .
    • Else return an object to the client, with status as true, and other user details which have been fetched from the database.
    • On the Client side, this user data is set in the localStorage for checking if the user is logged in or not using useEffect from react.

Sending Message

Implemented using the scket.io model

  global.onlineUsers = new Map();
  io.on("connection", (socket) => {
    global.chatSocket = socket;
    socket.on("add-user", (userId) => {
      onlineUsers.set(userId, socket.id);
    });

    socket.on("send-msg", (data) => {
      const sendUserSocket = onlineUsers.get(data.to);
      if (sendUserSocket) {
        socket.to(sendUserSocket).emit("msg-recieve", data.msg);
      }
    });
  });

we create a socket for each user and map to each userID. Whenever a new chat is selected and a message is send, it travels through the circuit, using the socket which has been mapped to the userID.

  • handleSendMsg function

      const handleSendMsg = async (msg) => {
        const data = await JSON.parse(
          localStorage.getItem(process.env.REACT_APP_LOCALHOST_KEY)
        );
        socket.current.emit("send-msg", {
          to: currentChat._id,
          from: data._id,
          msg,
        });
        await axios.post(sendMessageRoute, {
          from: data._id,
          to: currentChat._id,
          message: msg,
        });
    
        const msgs = [...messages];
        msgs.push({ fromSelf: true, message: msg });
        setMessages(msgs);
      };
    • Here socket.current is the socket associated with a particular userID.
    • socket.emit() is used for sending message to all user connected to that socket except self. Here socket.current maps to only one, thus the message is only sent to the current chat selected.
    • Also we store all the messages using our messageModel, so that they can be loaded onto to the client side in the future. Aparts, to succesfully access the correct messages in the future, we also need to store the from: data._id and to: currentChat._id



Configure the .env file as required and use npm install to install the required dependencies to run this web-app on your local system.
Suugesting Improvements are welcome!

You might also like...

ClientDB is an open source in-memory database for enabling real-time web apps.

ClientDB ClientDB is an open-source in-memory database for enabling real-time web apps. Build fast, scalable apps that feel silky smooth for users. In

Aug 27, 2022

A time-based one-time password (TOTP) generator and authenticator for Gun DB

A time-based one-time password (TOTP) generator and authenticator for Gun DB

Entangler A time-based one-time password (TOTP) generator and authenticator for Gun DB Entangler generates a 6 digit passcode every 30 seconds. It gen

Nov 9, 2022

🚀AI拟声: 5秒内克隆您的声音并生成任意语音内容 Clone a voice in 5 seconds to generate arbitrary speech in real-time

🚀AI拟声: 5秒内克隆您的声音并生成任意语音内容 Clone a voice in 5 seconds to generate arbitrary speech in real-time

English | 中文 Features 🌍 Chinese supported mandarin and tested with multiple datasets: aidatatang_200zh, magicdata, aishell3, and etc. 🤩 PyTorch work

Dec 29, 2022

A card for Home Assistant Lovelace for exploring the history of your entities interactively and in real time.

A card for Home Assistant Lovelace for exploring the history of your entities interactively and in real time.

History explorer card This is a custom history card for Home Assistant. This card offers a highly interactive and configurable way to view the history

Dec 31, 2022

Prototype of real-time comments and a proposal of how to make it "production-ready".

Prototype of real-time comments and a proposal of how to make it

Real-time comments prototype Simple demonstration of real-time commenting. Installation After forking it, run npm install, then you need two environme

Jan 16, 2022

Apollo - a JavaScript library to get real-time economic declarations such as inflation rates

Apollo is a JavaScript library to get real-time economic declarations such as inflation rates, unemployment rates or interest rates reported by governments or other entities.

Dec 10, 2022

Real-time event collaborating

Smartlist Collaborate Collaborate on your events in real-time! An product by Smartlist 🧪 This product is still in development, and some features mig

Mar 17, 2022

Clubhouse is a new type of social network based on voice—where people around the world come together to talk, listen and learn from each other in real-time.

Clubhouse is a new type of social network based on voice—where people around the world come together to talk, listen and learn from each other in real-time.

Awesome Clubhouse The clubhouse is a new type of social network based on voice—where people around the world come together to talk, listen and learn f

Nov 9, 2022

Cryptostat is a Node.js based CLI that gets you the real-time stats of your favorite cryptocurrency.

Cryptostat-CLI Cryptostat is a Node.js based CLI that gets you the real-time stats of your favorite cryptocurrency. Installation Use the npm package m

Dec 15, 2022
Owner
Sushmita Kumari
Sushmita Kumari
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
SCAchat - A self-hosted chatting application

SCAchat is a self-hosted chatting application similar to AOL Instant Messenger. The chatting application is privacy-respecting and does not store any messages or user-data. Once a session has ended, all messages are gone.

Chadano 4 Jul 18, 2022
CodePlay is a Web App that helps the user to input HTML,CSS and JS code in the Code editors and display the resultant web page in real-time

CodePlay A codepen clone Setup Clone repository Create and go to the directory where you want to place the repository cd my-directory Clone the proj

Aniket Kumar 5 Sep 24, 2022
A pure JavaScript Web Page to retrieve real-time OTP through a web page and generate/scan QR codes.

2FA-Solver A pure JavaScript Web Page to retrieve real-time OTP through a web page and generate/scan QR codes. It can be used as an offline web page b

Yuthan K 8 Dec 7, 2022
Download all Moodle files with one click. This is a Chrome extension built to save time and effort from downloading files manually one by one!

Moodle Downloader Extension Moodle downloader extension for Chrome. The extension is tested with both the TUM moodle and the official moodle demo. Not

Zhongpin Wang 8 Nov 15, 2022
A "Basic-to-Lisp" compiler. But Basic is not real Basic, and Lisp is not real Lisp.

Basic2Lisp A "Basic-to-Lisp" compiler. But Basic is not real Basic, and Lisp is not real Lisp. Syntax Print-Sth Put some-value to standard output. PRI

Hana Yabuki 5 Jul 10, 2022
Use real-time computing technology and web technology to build a big data Kanban l to solve the problem. Among them, practical technologies include MySQL, Kafka, Flink, Redis, Flask and Echarts

实时计算(English Version) 运用实时计算技术、Web 技术构建一个大数据看板来解决问题。其中实用技术包括Mysql、Kafka、Flink、Redis、Flask和Echarts 目录 1.问题需求 2.方案分析 3.安装环境 4.环境启动命令和运行代码的方法 5.代码目录结构说明

Serendipity 2 Jan 8, 2022
ClientDB is an open source in-memory database for enabling real-time web apps.

ClientDB ClientDB is an open source in-memory database for enabling real-time web apps. Build fast, scalable apps that feel silky smooth for users. In

Acapela 540 Dec 24, 2022