├── client ├── src │ ├── Components │ │ ├── tempCodeRunnerFile.js │ │ ├── Loading.js │ │ ├── Favourite.js │ │ ├── Chat.js │ │ ├── ShowPasswordToggle.js │ │ ├── Welcome.js │ │ ├── ErrorPage.js │ │ ├── Toggler.js │ │ ├── Searchbar.js │ │ ├── modal │ │ │ ├── NetworkError.js │ │ │ └── Invite.js │ │ ├── Loading1.js │ │ ├── ScrollToTopButton.js │ │ ├── Header.js │ │ ├── Default.js │ │ ├── Auth │ │ │ ├── Signup.js │ │ │ ├── Login.js │ │ │ ├── LoginForm.js │ │ │ └── ForgotPassword.js │ │ ├── Themes.js │ │ ├── Profile.js │ │ ├── Technologies.js │ │ ├── Footer.js │ │ ├── Contacts.js │ │ ├── Setting.js │ │ ├── Contact.js │ │ ├── Dropdown.js │ │ ├── SlideMenu │ │ │ └── UserProfile.js │ │ ├── ChatMenu.js │ │ ├── Features.js │ │ └── HeroSection.js │ ├── Redux │ │ ├── Reducer │ │ │ ├── Tab │ │ │ │ ├── tabType.js │ │ │ │ ├── tabAction.js │ │ │ │ └── tabReducer.js │ │ │ ├── SetColor │ │ │ │ ├── setColorType.js │ │ │ │ ├── setColorAction.js │ │ │ │ └── setColorReducer.js │ │ │ ├── Theme │ │ │ │ ├── theme.type.js │ │ │ │ ├── theme.action.js │ │ │ │ └── theme.reducer.js │ │ │ ├── ProfileImage │ │ │ │ ├── profileImage.type.js │ │ │ │ ├── profileImage.reducer.js │ │ │ │ └── profileImage.action.js │ │ │ ├── User │ │ │ │ ├── user.type.js │ │ │ │ ├── user.reducer.js │ │ │ │ └── user.action.js │ │ │ ├── Message │ │ │ │ ├── message.type.js │ │ │ │ ├── message.reducer.js │ │ │ │ └── message.action.js │ │ │ ├── Auth │ │ │ │ ├── auth.type.js │ │ │ │ ├── auth.reducer.js │ │ │ │ └── auth.action.js │ │ │ ├── Chat │ │ │ │ ├── chat.type.js │ │ │ │ ├── chat.reducer.js │ │ │ │ └── chat.action.js │ │ │ └── rootReducers.js │ │ └── Store.js │ ├── Pages │ │ ├── AuthPage.js │ │ └── HomePage.js │ ├── Layout │ │ └── DefaultLayout.js │ ├── App.css │ ├── Styles │ │ ├── Button.js │ │ ├── Spinner.js │ │ └── Social.js │ ├── index.js │ ├── index.css │ ├── HelperFunction │ │ └── chat.Helper.js │ ├── config.js │ │ └── data.js │ ├── GlobalStyle │ │ └── GlobalStyle.js │ └── App.js ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ ├── images │ │ ├── 1.png │ │ ├── 2.png │ │ ├── atom.png │ │ ├── logo.png │ │ ├── logo2.png │ │ ├── loading.gif │ │ ├── mongodb.png │ │ ├── shape-1.png │ │ ├── shape-3.png │ │ ├── shape-5.png │ │ ├── shape-6.png │ │ ├── tailwind.png │ │ ├── css-white.png │ │ ├── pattern-05.png │ │ ├── pattern-bg.png │ │ ├── googlefonts.png │ │ ├── html-5-white.png │ │ ├── nodejs-logo.png │ │ ├── contact-shape-1.png │ │ ├── contact-shape-2.png │ │ ├── features-icon-1.png │ │ ├── features-icon-2.png │ │ ├── features-icon-6.png │ │ └── email.svg │ ├── team │ │ ├── nitesh.png │ │ ├── narender.jpg │ │ └── rithuresh.jpg │ ├── manifest.json │ ├── social │ │ ├── facebook.svg │ │ └── twitter.svg │ └── index.html ├── postcss.config.js ├── .gitignore ├── tailwind.config.js ├── package.json └── README.md ├── server ├── config │ ├── keys.js │ ├── generateToken.js │ ├── db.js │ └── prod.js ├── .babelrc ├── utils │ ├── cloudinary.js │ └── sendEmail.js ├── routes │ ├── messageRoutes.js │ ├── chatRoutes.js │ └── userRoutes.js ├── models │ ├── messageModel.js │ ├── chatModel.js │ └── userModel.js ├── middleware │ ├── errorMiddleware.js │ └── authMiddleware.js ├── package.json ├── dist │ └── index.js ├── controllers │ ├── messageControllers.js │ └── chatControllers.js ├── data │ └── data.js └── index.js ├── .gitignore └── README.md /client/src/Components/tempCodeRunnerFile.js: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/Tab/tabType.js: -------------------------------------------------------------------------------- 1 | export const TOGGLE_TAB = "TOGGLE_TAB"; -------------------------------------------------------------------------------- /client/src/Redux/Reducer/SetColor/setColorType.js: -------------------------------------------------------------------------------- 1 | export const set_color = "set_color"; -------------------------------------------------------------------------------- /client/src/Redux/Reducer/Theme/theme.type.js: -------------------------------------------------------------------------------- 1 | export const TOGGLE_DARKTHEME = "TOGGLE_DARKTHEME"; -------------------------------------------------------------------------------- /client/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/favicon.ico -------------------------------------------------------------------------------- /client/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/logo192.png -------------------------------------------------------------------------------- /client/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/logo512.png -------------------------------------------------------------------------------- /client/src/Redux/Reducer/ProfileImage/profileImage.type.js: -------------------------------------------------------------------------------- 1 | export const UPLOAD_IMAGE = "UPLOAD_IMAGE"; 2 | -------------------------------------------------------------------------------- /client/public/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/1.png -------------------------------------------------------------------------------- /client/public/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/2.png -------------------------------------------------------------------------------- /client/public/images/atom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/atom.png -------------------------------------------------------------------------------- /client/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/logo.png -------------------------------------------------------------------------------- /client/public/images/logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/logo2.png -------------------------------------------------------------------------------- /client/public/team/nitesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/team/nitesh.png -------------------------------------------------------------------------------- /client/public/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/loading.gif -------------------------------------------------------------------------------- /client/public/images/mongodb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/mongodb.png -------------------------------------------------------------------------------- /client/public/images/shape-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/shape-1.png -------------------------------------------------------------------------------- /client/public/images/shape-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/shape-3.png -------------------------------------------------------------------------------- /client/public/images/shape-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/shape-5.png -------------------------------------------------------------------------------- /client/public/images/shape-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/shape-6.png -------------------------------------------------------------------------------- /client/public/images/tailwind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/tailwind.png -------------------------------------------------------------------------------- /client/public/team/narender.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/team/narender.jpg -------------------------------------------------------------------------------- /client/public/team/rithuresh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/team/rithuresh.jpg -------------------------------------------------------------------------------- /client/public/images/css-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/css-white.png -------------------------------------------------------------------------------- /client/public/images/pattern-05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/pattern-05.png -------------------------------------------------------------------------------- /client/public/images/pattern-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/pattern-bg.png -------------------------------------------------------------------------------- /client/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /client/public/images/googlefonts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/googlefonts.png -------------------------------------------------------------------------------- /client/public/images/html-5-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/html-5-white.png -------------------------------------------------------------------------------- /client/public/images/nodejs-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/nodejs-logo.png -------------------------------------------------------------------------------- /client/public/images/contact-shape-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/contact-shape-1.png -------------------------------------------------------------------------------- /client/public/images/contact-shape-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/contact-shape-2.png -------------------------------------------------------------------------------- /client/public/images/features-icon-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/features-icon-1.png -------------------------------------------------------------------------------- /client/public/images/features-icon-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/features-icon-2.png -------------------------------------------------------------------------------- /client/public/images/features-icon-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ideal-Softer/chat-app/HEAD/client/public/images/features-icon-6.png -------------------------------------------------------------------------------- /server/config/keys.js: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV == "production") { 2 | module.exports = require("./prod"); 3 | } else { 4 | module.exports = require("./dev"); 5 | } 6 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/Theme/theme.action.js: -------------------------------------------------------------------------------- 1 | import { TOGGLE_DARKTHEME } from "./theme.type"; 2 | 3 | export const toggleDarkTheme = () => ({ 4 | type: TOGGLE_DARKTHEME, 5 | }); -------------------------------------------------------------------------------- /client/src/Redux/Reducer/Tab/tabAction.js: -------------------------------------------------------------------------------- 1 | import { TOGGLE_TAB } from "./tabType"; 2 | 3 | export const toggleTab = (index ) => ({ 4 | type: TOGGLE_TAB, 5 | payload: index, 6 | }); 7 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/SetColor/setColorAction.js: -------------------------------------------------------------------------------- 1 | import { set_color } from "./setColorType"; 2 | 3 | export const toggleColor = (color) => ({ 4 | type: set_color, 5 | payload: color, 6 | }); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /client/node_modules 2 | /client/package-lock.json 3 | /client/.env 4 | 5 | /server/node_modules 6 | /server/package-lock.json 7 | server/.env 8 | server/vercel.json 9 | server/config/dev.js 10 | 11 | 12 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/User/user.type.js: -------------------------------------------------------------------------------- 1 | export const SELF = "SELF"; // PERSONAL DETAILS 2 | export const CLEAR_USER = "CLEAR_USER"; // SIGN OUT 3 | 4 | export const UPDATE_PROFILE = "UPDATE_PROFILE"; 5 | export const INVITE_FRIENDS = "INVITE_FRIENDS"; 6 | -------------------------------------------------------------------------------- /client/src/Pages/AuthPage.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Outlet } from "react-router-dom"; 3 | import DefaultLayoutHoc from "../Layout/DefaultLayout"; 4 | 5 | const AuthPage = () => { 6 | return ( 7 | <> 8 | 9 | 10 | ); 11 | }; 12 | 13 | export default DefaultLayoutHoc(AuthPage); 14 | -------------------------------------------------------------------------------- /server/config/generateToken.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | const { JWT_SECRET } = require("./keys"); 3 | 4 | const generateToken = (id, tokenValidity = "30d") => { 5 | // console.log(tokenValidity); 6 | return jwt.sign({ id }, JWT_SECRET, { 7 | expiresIn: tokenValidity, 8 | }); 9 | }; 10 | 11 | module.exports = generateToken; 12 | -------------------------------------------------------------------------------- /client/src/Layout/DefaultLayout.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const DefaultLayoutHoc = 4 | (Components) => 5 | ({ ...props }) => { 6 | return ( 7 | <> 8 |
9 | 10 |
11 | 12 | ); 13 | }; 14 | 15 | export default DefaultLayoutHoc; 16 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/Tab/tabReducer.js: -------------------------------------------------------------------------------- 1 | import { TOGGLE_TAB } from "./tabType"; 2 | 3 | const initialstate = 3 4 | 5 | const tabReducer = (state = initialstate, action) => { 6 | switch (action.type) { 7 | case TOGGLE_TAB: 8 | return state = action.payload; 9 | 10 | default: 11 | return state; 12 | } 13 | }; 14 | 15 | export default tabReducer; 16 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/Message/message.type.js: -------------------------------------------------------------------------------- 1 | export const SEND_MESSAGE = "SEND_MESSAGE"; 2 | export const GET_ALL_MESSAGE = "GET_ALL_MESSAGE"; 3 | export const UPDATE_GET_ALL_MESSAGE = "UPDATE_GET_ALL_MESSAGE"; 4 | export const CLEAR_ALL_MESSAGE = "CLEAR_ALL_MESSAGE"; 5 | export const SHOW_TOOGLE_LOADING = "SHOW_TOOGLE_LOADING"; 6 | export const SHOW_NETWORK_ERROR = "SHOW_NETWORK_ERROR" 7 | -------------------------------------------------------------------------------- /server/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/env", 5 | { 6 | "targets": { 7 | "node": "current" 8 | } 9 | } 10 | ] 11 | ], 12 | "plugins": [ 13 | "@babel/plugin-proposal-class-properties", 14 | "@babel/plugin-proposal-object-rest-spread" 15 | ] 16 | } -------------------------------------------------------------------------------- /server/utils/cloudinary.js: -------------------------------------------------------------------------------- 1 | const cloudinary = require("cloudinary").v2; 2 | const { 3 | CLOUDINARY_CLOUD_NAME, 4 | CLOUDINARY_API_KEY, 5 | CLOUDINARY_API_SECRET, 6 | } = require("../config/keys"); 7 | cloudinary.config({ 8 | cloud_name: CLOUDINARY_CLOUD_NAME, 9 | api_key: CLOUDINARY_API_KEY, 10 | api_secret: CLOUDINARY_API_SECRET, 11 | }); 12 | 13 | module.exports = cloudinary; 14 | -------------------------------------------------------------------------------- /server/routes/messageRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const { 3 | allMessages, 4 | sendMessage, 5 | } = require("../controllers/messageControllers"); 6 | const { protect } = require("../middleware/authMiddleware"); 7 | 8 | const router = express.Router(); 9 | 10 | router.route("/").post(protect, sendMessage); 11 | router.route("/:chatId").get(protect, allMessages); 12 | module.exports = router; 13 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/Auth/auth.type.js: -------------------------------------------------------------------------------- 1 | export const SIGN_IN = "SIGN_IN"; 2 | export const SIGN_UP = "SIGN_UP"; 3 | export const SIGN_OUT = "SIGN_OUT"; 4 | export const USER_VERIFICATION = "USER_VERIFICATION"; 5 | export const VERIFY_TOKEN = "VERIFY_TOKEN"; 6 | export const FORGOT_PASSWORD = "FORGOT_PASSWORD"; 7 | export const RESET_PASSWORD = "RESET_PASSWORD"; 8 | export const CLEAR_AUTH_STORE = "CLEAR_AUTH_STORE"; 9 | export const ERROR = "ERROR"; 10 | -------------------------------------------------------------------------------- /server/models/messageModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const messageModel = mongoose.Schema( 4 | { 5 | sender: { type: mongoose.Schema.Types.ObjectId, ref: "User" }, 6 | content: { type: String, trim: true }, 7 | chat: { type: mongoose.Schema.Types.ObjectId, ref: "Chat" }, 8 | }, 9 | { 10 | timestamps: true, 11 | } 12 | ); 13 | 14 | const Message = mongoose.model("Message", messageModel); 15 | 16 | module.exports = Message; 17 | -------------------------------------------------------------------------------- /client/src/Redux/Store.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from "redux"; 2 | import thunk from "redux-thunk"; 3 | import rootReducer from "./Reducer/rootReducers"; 4 | 5 | // redux middleware 6 | const middlewares = [thunk]; 7 | 8 | if (process.env.NODE_ENV === "development") { 9 | const { logger } = require("redux-logger"); 10 | middlewares.push(logger); 11 | } 12 | 13 | const Store = createStore(rootReducer, { 14 | 15 | }, applyMiddleware(...middlewares)); 16 | 17 | export default Store; 18 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/Chat/chat.type.js: -------------------------------------------------------------------------------- 1 | export const FETCH_CHATS = "FETCH_CHATS"; 2 | export const FETCH_USER = "FETCH_USER"; 3 | export const FETCH_USER_CLEAR = "FETCH_USER_CLEAR"; 4 | export const CREATE_CHAT = "CREATE_CHAT"; 5 | export const CREATE_GROUP_CHAT = "CREATE_GROUP_CHAT"; 6 | export const SELECT_CHAT = "SELECT_CHAT"; 7 | export const CLEAR_SELECT_CHAT = "CLEAR_SELECT_CHAT"; 8 | export const REMOVE_USER_FROM_GROUP = "REMOVE_USER_FROM_GROUP"; 9 | export const SHOW_USER_LOADING = "SHOW_TOOGLE_LOADING"; 10 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/ProfileImage/profileImage.reducer.js: -------------------------------------------------------------------------------- 1 | import { UPLOAD_IMAGE } from "./profileImage.type"; 2 | const initialState = { 3 | profilePic: "", 4 | }; 5 | 6 | const profileImageReducer = (state = initialState, action) => { 7 | switch (action.type) { 8 | case UPLOAD_IMAGE: 9 | return { 10 | ...state, 11 | profilePic: action.payload, 12 | }; 13 | 14 | default: 15 | return { 16 | ...state, 17 | }; 18 | } 19 | }; 20 | 21 | export default profileImageReducer; 22 | -------------------------------------------------------------------------------- /client/src/App.css: -------------------------------------------------------------------------------- 1 | .input-suffix-end { 2 | right: 0.625rem; 3 | } 4 | .input-suffix-end { 5 | --tw-translate-y: -50%; 6 | display: flex; 7 | position: absolute; 8 | } 9 | 10 | .input-wrapper { 11 | display: flex; 12 | position: relative; 13 | width: 100%; 14 | } 15 | 16 | .form-label { 17 | align-items: center; 18 | display: flex; 19 | font-weight: 500; 20 | } 21 | .form-item.vertical { 22 | display: flex; 23 | flex-direction: column; 24 | } 25 | .form-item { 26 | position: relative; 27 | margin-bottom: 1.75rem; 28 | } 29 | -------------------------------------------------------------------------------- /server/middleware/errorMiddleware.js: -------------------------------------------------------------------------------- 1 | const notFound = (req,res,next) => { 2 | const error = new Error(`Not Found - ${req.originalUrl}`); 3 | res.status(404); 4 | next(error); 5 | }; 6 | 7 | 8 | const errorHandler = (err,req,res,next) => { 9 | const statusCode = res.statusCode === 200 ? 500 : res.statusCode; 10 | res.status(statusCode); 11 | res.json({ 12 | message: err.message, 13 | stack: process.env.NODE_ENV === "production" ? null : err.stack, 14 | }); 15 | }; 16 | 17 | module.exports = { notFound, errorHandler}; -------------------------------------------------------------------------------- /client/src/Styles/Button.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export const Button = styled.button` 4 | font-weight: 400; 5 | line-height: 1.5; 6 | text-align: center; 7 | vertical-align: middle; 8 | cursor: pointer; 9 | -webkit-user-select: none; 10 | -ms-user-select: none; 11 | user-select: none; 12 | padding: 0.5rem 1rem; 13 | font-size: 0.9375rem; 14 | border-radius: 0.25rem; 15 | transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, 16 | border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; 17 | `; 18 | -------------------------------------------------------------------------------- /client/src/Components/Loading.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'styled-components'; 3 | 4 | const Loading = () => { 5 | return ( 6 | 7 | 8 | 9 | ) 10 | } 11 | 12 | const Wrapper = styled.section` 13 | width: 100vw; 14 | height: 100vh; 15 | h1 { 16 | font-size: 5rem; 17 | margin-bottom: 1rem 18 | } 19 | img { 20 | width: 8rem; 21 | margin-bottom: 2rem 22 | } 23 | 24 | `; 25 | 26 | export default Loading -------------------------------------------------------------------------------- /server/config/db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const dotenv = require("dotenv"); 3 | const { MONGO_URL } = require("./keys"); 4 | dotenv.config(); 5 | const connectDB = async () => { 6 | try { 7 | const conn = await mongoose.connect(MONGO_URL, { 8 | useNewUrlParser: true, 9 | useUnifiedTopology: true, 10 | }); 11 | 12 | console.log(`MongoDB Connected: ${conn.connection.host}`.cyan.underline); 13 | } catch (error) { 14 | console.log(`Error: ${error.message}`.red.bold); 15 | process.exit(); 16 | } 17 | }; 18 | 19 | module.exports = connectDB; 20 | -------------------------------------------------------------------------------- /client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /client/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{js,jsx,ts,tsx}"], 4 | 5 | theme: { 6 | extend: { 7 | colors: { 8 | primary: { 9 | 50: "#eff6ff", 10 | 100: "#dbeafe", 11 | 200: "#bfdbfe", 12 | 300: "#93c5fd", 13 | 400: "#60a5fa", 14 | 500: "#3b82f6", 15 | 600: "#2563eb", 16 | 700: "#1d4ed8", 17 | 800: "#1e40af", 18 | 900: "#1e3a8a", 19 | }, 20 | lightblue:{ 21 | 50:"#eff7fe" 22 | } 23 | }, 24 | }, 25 | }, 26 | plugins: [], 27 | }; 28 | -------------------------------------------------------------------------------- /server/config/prod.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | MONGO_URL: process.env.MONGO_URL, 3 | JWT_SECRET: process.env.JWT_SECRET, 4 | 5 | CLOUDINARY_CLOUD_NAME: process.env.CLOUDINARY_CLOUD_NAME, 6 | CLOUDINARY_API_KEY: process.env.CLOUDINARY_API_KEY, 7 | CLOUDINARY_API_SECRET: process.env.CLOUDINARY_API_SECRET, 8 | 9 | SMPT_SERVICES: process.env.SMPT_SERVICES, 10 | SMPT_MAIL: process.env.SMPT_MAIL, 11 | SMPT_PASSWORD: process.env.SMPT_PASSWORD, 12 | SMPT_HOST: process.env.SMPT_HOST, 13 | SMPT_PORT: process.env.SMPT_PORT, 14 | 15 | SMPT_HOST: process.env.SMPT_HOST, 16 | SMPT_PORT: process.env.SMPT_PORT, 17 | 18 | PORT: process.env.PORT, 19 | CLIENT_ACCESS_URL: process.env.CLIENT_ACCESS_URL, 20 | }; 21 | -------------------------------------------------------------------------------- /client/public/social/facebook.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /server/routes/chatRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const { 3 | accessChat, 4 | fetchChats, 5 | createGroupChat, 6 | renameGroup, 7 | removeFromGroup, 8 | addToGroup, 9 | } = require("../controllers/chatControllers"); 10 | const { protect } = require("../middleware/authMiddleware"); 11 | 12 | const router = express.Router(); 13 | 14 | router.route("/").post(protect, accessChat); 15 | router.route("/").get(protect, fetchChats); 16 | router.route("/group").post(protect, createGroupChat); 17 | router.route("/rename").put(protect,renameGroup); 18 | router.route("/groupremove").put(protect,removeFromGroup); 19 | router.route("/groupadd").put(protect,addToGroup); 20 | 21 | module.exports = router; 22 | -------------------------------------------------------------------------------- /client/src/Components/Favourite.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styled from "styled-components"; 3 | 4 | const Favourite = () => { 5 | return ( 6 | 7 |
8 |
9 |

Favourites

10 |
11 |
12 |
13 |
14 |

This Feature will be available Soon

15 |
16 |
17 | ); 18 | }; 19 | 20 | const Wrapper = styled.div` 21 | animation: fadeInLeft 1s; 22 | `; 23 | 24 | export default Favourite; 25 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/Theme/theme.reducer.js: -------------------------------------------------------------------------------- 1 | import { TOGGLE_DARKTHEME } from "./theme.type"; 2 | 3 | const initialstate ={ 4 | darkThemeEnabled: JSON.parse(localStorage.getItem("TOGGLE_DARKTHEME")) || false, 5 | } 6 | 7 | const themeReducer = (state = initialstate, action) => { 8 | switch (action.type) { 9 | case TOGGLE_DARKTHEME: 10 | state.darkThemeEnabled = !state.darkThemeEnabled 11 | const mode = localStorage.setItem("TOGGLE_DARKTHEME", JSON.stringify(state.darkThemeEnabled)) 12 | return { 13 | ...state, 14 | ...mode 15 | }; 16 | 17 | default: 18 | return state; 19 | } 20 | } 21 | 22 | export default themeReducer; 23 | 24 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/SetColor/setColorReducer.js: -------------------------------------------------------------------------------- 1 | import { set_color } from "./setColorType"; 2 | import { colors } from "../../../config.js/data"; 3 | 4 | const initialstate = { 5 | themeColor: JSON.parse(localStorage.getItem("set_color")) || colors[0].color 6 | } 7 | 8 | const setColorReducer = (state = initialstate, action) =>{ 9 | switch (action.type) { 10 | case set_color: 11 | state.themeColor = action.payload; 12 | const mode = localStorage.setItem("set_color", JSON.stringify(state.themeColor)) 13 | return { 14 | ...state, 15 | ...mode 16 | } 17 | default: 18 | return state; 19 | } 20 | 21 | 22 | } 23 | 24 | export default setColorReducer; -------------------------------------------------------------------------------- /client/src/Redux/Reducer/rootReducers.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from "redux"; 2 | 3 | // reducers or storage units 4 | import auth from "./Auth/auth.reducer"; 5 | import user from "./User/user.reducer"; 6 | import chat from "./Chat/chat.reducer"; 7 | import message from "./Message/message.reducer"; 8 | import profileImage from "./ProfileImage/profileImage.reducer"; 9 | import themeReducer from "./Theme/theme.reducer"; 10 | import tabReducer from "./Tab/tabReducer"; 11 | import setColorReducer from "./SetColor/setColorReducer" 12 | 13 | const rootReducer = combineReducers({ 14 | auth, 15 | user, 16 | profileImage, 17 | chat, 18 | message, 19 | themeReducer, 20 | tabReducer, 21 | setColorReducer 22 | }); 23 | 24 | export default rootReducer; 25 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/ProfileImage/profileImage.action.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { UPLOAD_IMAGE } from "./profileImage.type"; 3 | const SERVER_ACCESS_BASE_URL = process.env.REACT_APP_SERVER_ACCESS_BASE_URL; 4 | 5 | // profile picture update 6 | export const uploadProfilePicture = (image) => async (dispatch) => { 7 | try { 8 | const profileImage = await axios({ 9 | method: "PUT", 10 | url: `${SERVER_ACCESS_BASE_URL}/api/user/profilepic`, 11 | data: { image }, 12 | headers: { "Content-Type": "multipart/form-data" }, 13 | }); 14 | // console.log(profileImage.data); 15 | return dispatch({ type: UPLOAD_IMAGE, payload: image }); 16 | } catch (error) { 17 | return dispatch({ type: "ERROR", payload: error }); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { BrowserRouter } from "react-router-dom"; 4 | import "./index.css"; 5 | import App from "./App"; 6 | 7 | // Redux 8 | import { Provider } from "react-redux"; 9 | import Store from "./Redux/Store"; 10 | import axios from "axios"; 11 | 12 | if (localStorage.ETalkUser) { 13 | const { token } = JSON.parse(localStorage.ETalkUser); 14 | axios.defaults.headers.common["Authorization"] = `Bearer ${token}`; 15 | } 16 | 17 | const root = ReactDOM.createRoot(document.getElementById("root")); 18 | root.render( 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | -------------------------------------------------------------------------------- /server/models/chatModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const chatModel = mongoose.Schema( 4 | { 5 | chatName: { type: String, trim: true }, 6 | isGroupChat: { type: Boolean, default: false }, 7 | users: [ 8 | { 9 | type: mongoose.Schema.Types.ObjectId, 10 | ref: "User", 11 | }, 12 | ], 13 | latestMessage: { 14 | type: mongoose.Schema.Types.ObjectId, 15 | ref: "Message", 16 | }, 17 | groupAdmin: { 18 | type: mongoose.Schema.Types.ObjectId, 19 | ref: "User", 20 | }, 21 | }, 22 | { 23 | timestamps: true, 24 | } 25 | ); 26 | 27 | const Chat = mongoose.model("Chat", chatModel); 28 | 29 | module.exports = Chat; 30 | 31 | // chatName 32 | // isGroup 33 | // users 34 | // latrestUser 35 | // groupAdmin 36 | -------------------------------------------------------------------------------- /client/src/index.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;500;600;700;800;900&display=swap'); 2 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700;900&display=swap'); 3 | @tailwind base; 4 | @tailwind components; 5 | @tailwind utilities; 6 | 7 | body { 8 | margin: 0; 9 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 10 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 11 | sans-serif; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | overflow-x: hidden; 15 | background-color: #f7f7ff; 16 | 17 | } 18 | 19 | code { 20 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 21 | monospace; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /client/public/social/twitter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/Redux/Reducer/User/user.reducer.js: -------------------------------------------------------------------------------- 1 | import { SELF, CLEAR_USER, UPDATE_PROFILE, INVITE_FRIENDS } from "./user.type"; 2 | 3 | const initialState = { 4 | user: {}, 5 | }; 6 | 7 | const userReducer = (state = initialState, action) => { 8 | switch (action.type) { 9 | case SELF: 10 | return { 11 | ...state, 12 | ...action.payload, 13 | }; 14 | case CLEAR_USER: 15 | return { 16 | user: {}, 17 | }; 18 | case UPDATE_PROFILE: 19 | return { 20 | ...state, 21 | ...action.payload, 22 | }; 23 | case INVITE_FRIENDS: 24 | return { 25 | ...state, 26 | InvitingStatus: { ...action.payload }, 27 | }; 28 | default: 29 | return { 30 | ...state, 31 | }; 32 | } 33 | }; 34 | 35 | export default userReducer; 36 | -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | E-Talk 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /server/utils/sendEmail.js: -------------------------------------------------------------------------------- 1 | const nodeMailer = require("nodemailer"); 2 | const { 3 | SMPT_HOST, 4 | SMPT_PORT, 5 | SMPT_SERVICES, 6 | SMPT_MAIL, 7 | SMPT_PASSWORD, 8 | } = require("../config/keys"); 9 | const sendEmail = async (options) => { 10 | const transporter = nodeMailer.createTransport({ 11 | host: SMPT_HOST, 12 | port: SMPT_PORT, 13 | service: SMPT_SERVICES, 14 | auth: { 15 | user: SMPT_MAIL, 16 | pass: SMPT_PASSWORD, 17 | }, 18 | }); 19 | const mailOptions = { 20 | from: SMPT_MAIL, 21 | to: options.email, 22 | subject: options.subject, 23 | html: options.message_Content, 24 | }; 25 | const mailInfo = await transporter.sendMail(mailOptions, (error, result) => { 26 | if (error) { 27 | // console.log(error); 28 | } 29 | }); 30 | 31 | // console.log(mailInfo); 32 | }; 33 | 34 | module.exports = sendEmail; 35 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js", 8 | "dev": "nodemon index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "bcryptjs": "^2.4.3", 14 | "cloudinary": "^1.34.0", 15 | "colors": "^1.4.0", 16 | "cors": "^2.8.5", 17 | "dotenv": "^16.0.3", 18 | "express": "^4.18.2", 19 | "express-async-handler": "^1.2.0", 20 | "helmet": "^6.0.1", 21 | "jsonwebtoken": "^8.5.1", 22 | "mongoose": "^6.7.2", 23 | "multer": "^1.4.5-lts.1", 24 | "nodemailer": "^6.9.1", 25 | "socket.io": "^4.6.1" 26 | }, 27 | "devDependencies": { 28 | "@babel/cli": "^7.19.3", 29 | "@babel/core": "^7.20.2", 30 | "@babel/node": "^7.20.2", 31 | "@babel/preset-env": "^7.20.2", 32 | "nodemon": "^2.0.20" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /client/src/Components/Chat.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { Route, Routes } from "react-router-dom"; 3 | import styled from "styled-components"; 4 | import ChatMenu from "./ChatMenu"; 5 | import ChatWindow from "./ChatWindow"; 6 | import SideMenu from "./SideMenu"; 7 | import { ToastContainer} from "react-toastify"; 8 | import NetworkError from "./modal/NetworkError"; 9 | import { useSelector } from "react-redux"; 10 | const Chat = () => { 11 | 12 | const isNetworkError = useSelector((globalstate)=> globalstate.message.NetworkError) 13 | 14 | return ( 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ); 24 | }; 25 | const Wrapper = styled.section` 26 | overflow: hidden; 27 | height: 100vh; 28 | transition: all 0.5s; 29 | `; 30 | 31 | export default Chat; 32 | -------------------------------------------------------------------------------- /client/src/Components/ShowPasswordToggle.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useState } from "react"; 3 | import { AiFillEye, AiOutlineEyeInvisible } from "react-icons/ai"; 4 | 5 | const ShowPasswordToggle = () => { 6 | const [visible, setVisible] = useState(false); 7 | const InputType = visible ? "text" : "password"; 8 | 9 | const Icon = ( 10 |
11 | 12 | {visible ? ( 13 | setVisible(false)} 16 | /> 17 | ) : ( 18 | setVisible(true)} 21 | /> 22 | )} 23 | 24 |
25 | ) 26 | 27 | 28 | return [Icon, InputType]; 29 | }; 30 | 31 | export default ShowPasswordToggle; 32 | -------------------------------------------------------------------------------- /server/middleware/authMiddleware.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | const User = require("../models/userModel.js"); 3 | const asyncHandler = require("express-async-handler"); 4 | const { JWT_SECRET } = require("../config/keys"); 5 | 6 | const protect = asyncHandler(async (req, res, next) => { 7 | let token; 8 | 9 | if ( 10 | req.headers.authorization && 11 | req.headers.authorization.startsWith("Bearer") 12 | ) { 13 | try { 14 | token = req.headers.authorization.split(" ")[1]; 15 | 16 | //decodes token id 17 | const decoded = jwt.verify(token, JWT_SECRET); 18 | 19 | req.user = await User.findById(decoded.id).select("-password"); 20 | 21 | next(); 22 | } catch (error) { 23 | res.status(401); 24 | throw new Error("Not authorized, token failed"); 25 | } 26 | } 27 | 28 | if (!token) { 29 | res.status(401); 30 | throw new Error("Not authorized, no token"); 31 | } 32 | }); 33 | 34 | module.exports = { protect }; 35 | -------------------------------------------------------------------------------- /client/src/Styles/Spinner.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styled from "styled-components"; 3 | 4 | const Spinner = () => { 5 | return ( 6 | 7 |
11 | 12 | Loading... 13 | 14 |
15 |
16 | ); 17 | }; 18 | 19 | export default Spinner; 20 | 21 | const Wrapper = styled.div` 22 | width: 100%; 23 | height: 100%; 24 | display: flex; 25 | justify-content: center; 26 | div { 27 | width: 8rem; 28 | height: 8rem; 29 | color: ${({ theme }) => theme.colors.primaryRgb}; 30 | } 31 | ` 32 | -------------------------------------------------------------------------------- /client/src/Styles/Social.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { FcGoogle } from "react-icons/fc"; 3 | import styled from "styled-components"; 4 | import { Button } from "./Button"; 5 | 6 | const Social = () => { 7 | return ( 8 | 9 |
10 | or 11 |
Sign in With
12 |
13 |
14 |
15 | 23 |
24 |
25 |
26 | ); 27 | }; 28 | 29 | const Wrapper = styled.section` 30 | `; 31 | 32 | export default Social; 33 | -------------------------------------------------------------------------------- /client/src/Components/Welcome.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Contact from "./Contact"; 3 | import Features from "./Features"; 4 | import Team from "./Team"; 5 | import Footer from "./Footer"; 6 | 7 | import Header from "./Header"; 8 | import HeroSection from "./HeroSection"; 9 | import Technologies from "./Technologies"; 10 | import ScrollToTopButton from "./ScrollToTopButton"; 11 | import styled from "styled-components"; 12 | 13 | 14 | 15 | const Welcome = () => { 16 | 17 | return ( 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |