{"id":16601580,"url":"https://github.com/amankumarsinhagithub/mern","last_synced_at":"2025-04-12T04:23:29.098Z","repository":{"id":252648853,"uuid":"839617702","full_name":"AmanKumarSinhaGitHub/MERN","owner":"AmanKumarSinhaGitHub","description":"🚀 Complete MERN Stack Guide for Beginners |  MongoDB • ExpressJs •  React • NodeJs  | Become Pro Coder","archived":false,"fork":false,"pushed_at":"2025-04-05T15:46:25.000Z","size":3570,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-05T16:32:15.955Z","etag":null,"topics":["backend","express","front-end","full-stack","mern","mern-crud","mern-project","mern-projects","mern-stack","mern-stack-development","mongodb","nodejs","react","web-development"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AmanKumarSinhaGitHub.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-08T01:41:42.000Z","updated_at":"2025-04-05T15:46:28.000Z","dependencies_parsed_at":"2024-11-01T15:26:44.039Z","dependency_job_id":"1259aa00-5249-43a5-81d6-6ac4873b4f05","html_url":"https://github.com/AmanKumarSinhaGitHub/MERN","commit_stats":null,"previous_names":["amankumarsinhagithub/mern"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmanKumarSinhaGitHub%2FMERN","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmanKumarSinhaGitHub%2FMERN/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmanKumarSinhaGitHub%2FMERN/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmanKumarSinhaGitHub%2FMERN/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AmanKumarSinhaGitHub","download_url":"https://codeload.github.com/AmanKumarSinhaGitHub/MERN/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248514730,"owners_count":21117017,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend","express","front-end","full-stack","mern","mern-crud","mern-project","mern-projects","mern-stack","mern-stack-development","mongodb","nodejs","react","web-development"],"created_at":"2024-10-12T00:18:34.707Z","updated_at":"2025-04-12T04:23:29.081Z","avatar_url":"https://github.com/AmanKumarSinhaGitHub.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MERN Stack\n\nWelcome to the MERN Stack! This guide will help you set up a MERN stack application step-by-step.\n\n## License\n\nThis project is licensed under the [Creative Commons Attribution-NonCommercial 4.0 International License](https://creativecommons.org/licenses/by-nc/4.0/).\n\n[![License: CC BY-NC 4.0](https://img.shields.io/badge/License-CC%20BY--NC%204.0-lightgrey.svg)](https://creativecommons.org/licenses/by-nc/4.0/)\n\n## Prerequisites\n\n- **Node.js and npm**: Ensure that Node.js and npm (Node Package Manager) are installed on your machine. These are essential for running JavaScript on the server and managing dependencies.\n- **Basic knowledge of JavaScript**: Familiarity with JavaScript syntax and concepts will help you follow along more easily.\n\n## Folder Structure\n\nWe'll start by organizing our project into two main folders:\n\n1. **`frontend`**: This folder will contain all the files related to the client-side of our application, which is built using React.js.\n2. **`backend`**: This folder will contain the server-side code, where we'll handle data processing, business logic, and communication with the database.\n\n## Day 1: Backend Setup\n\n### Introduction\n\nThe backend of a MERN application is where the core logic resides. It handles tasks such as processing requests, interacting with databases, and sending responses. We'll use **Express.js**, a fast and minimalist web framework for Node.js, to build our server.\n\n### Step 1: Navigate to the Backend Folder\n\nStart by navigating to the `backend` folder where we'll set up our server:\n\n```bash\ncd backend\n```\n\n### Step 2: Initialize a Node.js Project\n\nWe need to initialize our backend project by creating a `package.json` file. This file keeps track of our project's metadata and dependencies.\n\n```bash\nnpm init -y\n```\n\n### Step 3: Install Express.js\n\n**Express.js** is a popular framework for building web servers in Node.js. It simplifies the process of handling HTTP requests, routing, and middleware.\n\n```bash\nnpm install express\n```\n\n### Step 4: Create the Server\n\nNow, create a file named `index.js`. This file will contain the code to set up a basic Express server. The server listens for incoming requests and responds with a simple message.\n\n```js\nconst express = require(\"express\");\nconst app = express();\n\napp.get(\"/\", (req, res) =\u003e {\n  res.send(\"Hello World\");\n});\n\nconst PORT = 3000;\n\napp.listen(PORT, () =\u003e {\n  console.log(`Server is running on port ${PORT}`);\n});\n```\n\n### Step 5: Run the Server\n\nTo start the server, we'll use **Nodemon**, a tool that automatically restarts the server whenever you make changes to your code. This makes the development process more efficient.\n\n```bash\nnodemon index.js\n```\n\nIf you haven't installed `nodemon`, you can do so globally with:\n\n```bash\nnpm install -g nodemon\n```\n\nOpen your browser and navigate to `http://localhost:3000` to see the \"Hello World\" message from your server.\n\n## Day 2: Router in Express.js\n\n### Introduction\n\nRouting is a critical aspect of any web application. It determines how an application responds to different HTTP requests (e.g., GET, POST) for specific endpoints (URLs). **Express.js** provides a powerful and flexible routing system that helps you manage the different parts of your application more effectively.\n\n### Creating and Organizing Routes\n\nRoutes help you define specific endpoints in your application and map them to the corresponding logic. This makes your code more modular and easier to maintain.\n\n#### Step 1: Create Router Folder and File\n\nTo keep our routes organized, we'll create a new folder named `router` inside the `backend` folder. Within this folder, create a file named `auth-router.js`. This file will handle the routes related to authentication.\n\nAdd the following code to `auth-router.js`:\n\n```js\nconst express = require(\"express\");\nconst router = express.Router();\n\n// Basic route setup using Router\nrouter.route(\"/\").get((req, res) =\u003e {\n  res.send(\"Hello World using Router\");\n});\n\nmodule.exports = router;\n```\n\n#### Step 2: Update `index.js`\n\nNow, we'll modify `index.js` to include our new router. This allows us to separate concerns and keep our main server file clean.\n\n```js\nconst express = require(\"express\");\nconst app = express();\n\nconst router = require(\"./router/auth-router\");\napp.use(\"/api/auth\", router);\n\napp.get(\"/\", (req, res) =\u003e {\n  res.send(\"Hello World\");\n});\n\nconst PORT = 3000;\n\napp.listen(PORT, () =\u003e {\n  console.log(`Server is running on port ${PORT}`);\n});\n```\n\nWith these changes:\n\n- Visiting `http://localhost:3000` will still display \"Hello World\".\n- Visiting `http://localhost:3000/api/auth` will display \"Hello World using Router\", showcasing our new route setup.\n\n## Day 3: Controllers in Express.js\n\n### Introduction\n\nControllers are a key part of the **MVC (Model-View-Controller)** design pattern. They are responsible for processing incoming requests, interacting with the data layer (models), and sending responses back to the client. By using controllers, we can keep our application logic organized and modular.\n\n### Step 1: Create Controllers Folder and File\n\nIn the `backend` folder, create a new folder named `controllers` and a file named `auth-controller.js`. This file will contain the logic for handling authentication-related requests.\n\nAdd the following code to `auth-controller.js`:\n\n```js\nconst home = async (req, res) =\u003e {\n  try {\n    res.send(\"Welcome to the home page using controllers\");\n  } catch (error) {\n    console.log(error);\n  }\n};\n\nconst register = async (req, res) =\u003e {\n  try {\n    res.send(\"Welcome to the register page using controller\");\n  } catch (error) {\n    console.log(error);\n  }\n};\n\nmodule.exports = { home, register };\n```\n\n### Step 2: Update `auth-router.js`\n\nNext, update the `auth-router.js` file to use the new controller functions. This will link the routes to the appropriate logic in the controllers.\n\n```js\nconst express = require(\"express\");\nconst router = express.Router();\nconst { home, register } = require(\"../controllers/auth-controller\");\n\nrouter.route(\"/\").get(home);\nrouter.route(\"/register\").post(register);\n\nmodule.exports = router;\n```\n\n### Final Check\n\n- Visit `http://localhost:3000` to see the basic \"Hello World\" message.\n- Visit `http://localhost:3000/api/auth` to see the \"Hello World using Router\" message.\n- Visit `http://localhost:3000/api/auth/register` to see the \"Welcome to the register page using controller\" message.\n\n## Day 4: Middlewares and Testing API using Postman\n\n### Introduction\n\nMiddlewares are functions that execute during the lifecycle of a request to the Express server. They have access to the request object, response object, and the next middleware function in the application’s request-response cycle. Middlewares are crucial for adding functionality such as parsing request bodies, handling authentication, or logging requests.\n\n### Step 1: Add JSON Middleware\n\nTo test API requests, we'll need to parse incoming JSON data. Express provides a built-in middleware `express.json()` that parses incoming requests with JSON payloads. It should be added at the beginning of your middleware stack to ensure it is available for all subsequent route handlers.\n\n```js\nconst express = require(\"express\");\nconst app = express();\n\nconst router = require(\"./router/auth-router\");\n\n// Middleware\napp.use(express.json());\n\napp.use(\"/api/auth\", router);\n\napp.get(\"/\", (req, res) =\u003e {\n  res.send(\"Hello World\");\n});\n\nconst PORT = 3000;\n\napp.listen(PORT, () =\u003e {\n  console.log(`Server is running on port ${PORT}`);\n});\n```\n\n### Step 2: Update the Register Route\n\nEnsure the register route is set to handle POST requests, as this is the standard for creating resources or submitting data.\n\n```js\nconst express = require(\"express\");\nconst router = express.Router();\nconst { home, register } = require(\"../controllers/auth-controller\");\n\nrouter.route(\"/\").get(home);\nrouter.route(\"/register\").post(register);\n\nmodule.exports = router;\n```\n\n### Step 3: Handle the Register Logic\n\nModify the `register` function in `auth-controller.js` to handle and respond with the JSON data:\n\n```js\nconst home = async (req, res) =\u003e {\n  try {\n    res.send(\"Welcome to the home page using controller\");\n  } catch (error) {\n    console.log(error);\n  }\n};\n\nconst register = async (req, res) =\u003e {\n  try {\n    console.log(req.body); // Log the incoming request body\n    res.json({ message: \"User registered successfully\", data: req.body });\n  } catch (error) {\n    console.log(error);\n  }\n};\n\nmodule.exports = { home, register };\n```\n\n### Step 4: Test with Postman\n\nTo test the API with Postman:\n\n1. Set the request type to `POST`.\n2. Enter `http://localhost:3000/api/auth/register` in the URL.\n3. In the Headers tab, add `Content-Type` as the key and `application/json` as the value.\n4. In the Body tab, select `raw` and `JSON` from the dropdown, then enter the following JSON:\n\n```json\n{\n  \"email\": \"amankrsinha07@gmail.com\",\n  \"password\": 12334\n}\n```\n\n5. Click `Send` to make the request. You should see the response containing the JSON data you sent.\n\n- For visual reference, check the screenshots provided:\n\n- ![Header-Postman](./screenshots/auth-register-header.png)\n- ![Body-Postman](./screenshots/auth-register-body.png)\n\n## Day 4: Connecting Backend with MongoDB\n\nIn this section, we'll connect our backend to MongoDB, a NoSQL database that stores data in flexible, JSON-like documents. We will use **Mongoose**, an ODM (Object Data Modeling) library, to interact with MongoDB in a more structured and efficient way.\n\n### Step 1: Install Required Packages\n\nFirst, install the necessary packages for MongoDB connection and environment variable management:\n\n```bash\nnpm install mongodb mongoose dotenv\n```\n\n### Step 2: Set Up MongoDB Atlas\n\nTo use MongoDB in a cloud environment, follow these steps to set up MongoDB Atlas:\n\n1. **Create a MongoDB Atlas Account:**\n\n   - Visit [MongoDB Atlas](https://www.mongodb.com/cloud/atlas/register) and log in or sign up for an account.\n\n2. **Create a New Project:**\n\n   - After logging in, create a new project in MongoDB Atlas.\n\n   - ![create project](./screenshots/create_project.png)\n   - ![create project](./screenshots/create_project2.png)\n   - ![create project](./screenshots/create_project3.png)\n\n3. **Configure Network Access:**\n\n   - In the security section, open the **Network Access** tab.\n   - Add your current IP address to allow access from your machine.\n   - If you want to access your database from any computer, then add this IP also `0.0.0.0/0`\n\n   - ![network access](./screenshots/network_access.png)\n\n4. **Create a Database User:**\n\n   - In the **Database Access** tab, add a new user with `Read and Write` permissions.\n\n   - ![databse project](./screenshots/database_access.png)\n\n5. **Create a Cluster:**\n\n   - Go to the **Deployment** section and create a new cluster. Choose your preferred configuration.\n\n   - ![create cluster](./screenshots/creating_cluster.png)\n\n6. **Connect to Your Cluster:**\n\n   - After the cluster is created, click on the **Connect** button.\n\n   - ![connect](./screenshots/connecting.png)\n\n   - Choose a connection method\n\n   - ![connect method](./screenshots/connect_using.png)\n\n   - Get the connection string, which will look something like this:\n\n   ```\n   mongodb+srv://\u003cusername\u003e:\u003cpassword\u003e@\u003ccluster_name\u003e.mongodb.net\n   ```\n\n   - ![connection string](./screenshots/connection_string.png)\n\n### Step 3: Set Up Environment Variables\n\nCreate a `.env` file in the root directory of the `backend` folder and add the following content:\n\n```bash\nPORT=3000\nMONGO_URI=mongodb+srv://\u003cusername\u003e:\u003cpassword\u003e@\u003ccluster_name\u003e.mongodb.net\n```\n\nReplace `\u003cusername\u003e`, `\u003cpassword\u003e`, and `\u003ccluster_name\u003e` with the actual values from your MongoDB Atlas connection string.\n\n### Step 4: Create a Database Utility File\n\nTo manage the MongoDB connection, create a new folder named `utils` in the `backend` directory and inside it, create a file named `db.js` with the following code:\n\n```js\nconst mongoose = require(\"mongoose\");\n\nconst URI = process.env.MONGO_URI;\n\nconst connectDB = async () =\u003e {\n  if (!URI) {\n    console.error(\"MongoDB URI is not defined\");\n    process.exit(1); // Exit if URI is not set\n  }\n\n  try {\n    const conn = await mongoose.connect(URI, {\n      dbName: \"mern\", // Replace with your actual database name\n    });\n    console.log(\"MongoDB Database Connected Successfully\");\n  } catch (error) {\n    console.error(`Error: ${error.message}`);\n    process.exit(1);\n  }\n};\n\nmodule.exports = connectDB;\n```\n\nThis utility file will handle the connection to the MongoDB database.\n\n### Step 5: Integrate MongoDB Connection into the Server\n\nNow, modify your `index.js` file to use the `connectDB` function for connecting to MongoDB before starting the server:\n\n```js\nrequire(\"dotenv\").config();\nconst express = require(\"express\");\nconst app = express();\nconst router = require(\"./router/auth-router\");\nconst connectDB = require(\"./utils/db\");\n\n// Middleware\napp.use(express.json());\napp.use(\"/api/auth\", router);\n\napp.get(\"/\", (req, res) =\u003e {\n  res.send(\"Hello World\");\n});\n\n// Connect to the database and start the server\nconnectDB()\n  .then(() =\u003e {\n    const PORT = process.env.PORT || 3000;\n    app.listen(PORT, () =\u003e {\n      console.log(`Server is running on port ${PORT}`);\n    });\n    console.log(\"Database connected\");\n  })\n  .catch((err) =\u003e {\n    console.error(\"Database connection failed\", err);\n    process.exit(1);\n  });\n```\n\n## Day 5 - User Model and Schema\n\n### Understanding Schema and Model:\n\n- **Schema**:\n  - Defines the structure of the documents within a MongoDB collection.\n  - Specifies the fields, their types, and additional constraints or validation rules.\n- **Model**:\n  - A higher-level abstraction that interacts with the database based on the defined schema.\n  - Represents a collection and provides an interface for querying, creating, updating, and deleting documents in that collection.\n  - Models are created from schemas and enable you to work with MongoDB data in a more structured manner in your application.\n\n### Steps:\n\n1. **Create the `model` Folder**:\n\n   - In the `backend` directory, create a new folder named `model`.\n\n2. **Create the `user-model.js` File**:\n   - Inside the `model` folder, create a file named `user-model.js`.\n   - Define the `userSchema` and `User` model as follows:\n\n```js\nconst mongoose = require(\"mongoose\");\n\nconst userSchema = new mongoose.Schema({\n  username: {\n    type: String,\n    required: true,\n  },\n  email: {\n    type: String,\n    required: true,\n    unique: true,\n  },\n  phone: {\n    type: Number,\n    required: true,\n  },\n  password: {\n    type: String,\n    required: true,\n  },\n  isAdmin: {\n    type: Boolean,\n    default: false,\n  },\n});\n\nconst User = mongoose.model(\"User\", userSchema);\nmodule.exports = User;\n```\n\n### Explanation:\n\n- **Fields**:\n  - `username`, `email`, `phone`, and `password` are required fields.\n  - `email` is also unique, meaning no two users can have the same email address.\n  - `isAdmin` is a boolean field with a default value of `false`, indicating whether the user has admin privileges.\n\n## Day 6 - Storing Registered User Data in MongoDB Using Postman\n\nIn this step, we will update our `auth-controller.js` to store registered user data in the MongoDB database. We'll validate the input data, check if the user already exists, and then create a new user record if everything is valid.\n\n### Step 1: Update `auth-controller.js`\n\nMake the following changes to your `auth-controller.js`:\n\n```js\nconst User = require(\"../models/user-model\");\n\nconst home = async (req, res) =\u003e {\n  try {\n    res.send(\"Welcome to the home page using controller\");\n  } catch (error) {\n    console.error(error);\n  }\n};\n\nconst register = async (req, res) =\u003e {\n  try {\n    console.log(req.body);\n\n    const { username, email, phone, password } = req.body;\n\n    // Check if any field is empty\n    if (!username || !email || !phone || !password) {\n      return res.status(400).json({ message: \"Please fill all the fields\" });\n    }\n\n    // Check if the user already exists (email)\n    const userExists = await User.findOne({ email });\n    if (userExists) {\n      return res.status(400).json({ message: \"User already exists\" });\n    }\n\n    // Create a new user\n    const user = await User.create({\n      username,\n      email,\n      phone,\n      password,\n    });\n\n    res.status(201).json({ message: \"User registered successfully\", user });\n    console.log(user);\n  } catch (error) {\n    console.error(error);\n    res.status(500).json({ message: \"Server error. Please try again later.\" });\n  }\n};\n\nmodule.exports = { home, register };\n```\n\n### Explanation:\n\n1. **Field Validation**: The code first checks if all required fields (`username`, `email`, `phone`, and `password`) are provided. If any field is missing, it returns a `400 Bad Request` response with a message indicating that all fields must be filled.\n\n2. **User Existence Check**: It then checks if a user with the same email already exists in the database. If the user is found, it returns a `400 Bad Request` response with a message indicating that the user already exists.\n\n3. **User Creation**: If the user does not exist, the code creates a new user document in the database with the provided data and returns a `201 Created` response, indicating that the user was successfully registered.\n\n4. **Error Handling**: Any errors during the process are caught, logged, and a `500 Internal Server Error` response is sent to the client.\n\n### Step 2: Test the Registration Endpoint Using Postman\n\nNow, you can test the registration functionality using Postman:\n\n1. **Open Postman**:\n\n   - Set the request type to `POST`.\n   - Enter the URL: `http://localhost:3000/api/auth/register`.\n\n2. **Headers**:\n\n   - Ensure the `Content-Type` header is set to `application/json`.\n\n3. **Body**:\n\n   - Select `raw` and choose `JSON` from the dropdown.\n   - Enter the following JSON data in the body:\n     ```json\n     {\n       \"username\": \"aman\",\n       \"email\": \"amankrsinha07@gmail.com\",\n       \"phone\": \"9876543210\",\n       \"password\": \"12345\"\n     }\n     ```\n\n4. **Send the Request**:\n   - Click `Send` to register the new user.\n   - If successful, you should see a response with the message \"User registered successfully\" and the user data.\n\n#### Screenshot References:\n\n- **Register Using Postman**:\n\n  - ![Register using Postman](./screenshots/user_register_using_postman.png)\n\n- **User Data in MongoDB Atlas**:\n\n  - ![User data in Atlas](./screenshots/user_in_atlas.png)\n\n- **User Data in MongoDB Compass**:\n  - ![User data in Compass](./screenshots/user_in_compass.png)\n\n### Conclusion:\n\nBy following these steps, you've successfully implemented a feature to store registered user data in MongoDB. You've also learned how to validate input data, check for existing users, and handle errors, all while testing the functionality using Postman.\n\nThis is a crucial step in building your MERN stack application, as user registration is often the first interaction users have with your backend system.\n\n## Day 7 - Secure User Password Using Bcrypt.js\n\nTo enhance the security of your application, it is crucial to hash passwords before storing them in the database. This ensures that even if your database is compromised, the stored passwords remain secure.\n\n### Step 1: Install Bcrypt.js\n\nFirst, you'll need to install the `bcryptjs` package, which will help you hash passwords.\n\n```bash\nnpm i bcryptjs\n```\n\n### Step 2: Update `auth-controller.js`\n\nNow, modify your `auth-controller.js` to hash the user's password before saving it to the database:\n\n```js\nconst bcrypt = require(\"bcryptjs\");\n\n// Hashing the password before creating user\nconst saltRounds = 10;\nconst hashedPassword = await bcrypt.hash(String(password), saltRounds);\n\n// Create a new user with the hashed password\nconst user = await User.create({\n  username,\n  email,\n  phone,\n  password: hashedPassword,\n});\n```\n\n### Explanation:\n\n1. **Bcrypt.js Import**: We first import `bcryptjs` to use its hashing functionality.\n\n2. **Salt Rounds**: The `saltRounds` variable defines the cost factor, which is the number of times the hashing algorithm will be applied. A higher number increases the computation time, making it harder for attackers to crack the password.\n\n3. **Hashing the Password**:\n\n   - The `bcrypt.hash()` method takes two arguments: the password to hash and the number of salt rounds.\n   - The `String(password)` ensures that the password is converted to a string before hashing.\n   - The hashed password is then stored in the `hashedPassword` variable.\n\n4. **Creating the User**:\n   - Instead of storing the plain password, we store the `hashedPassword` in the database when creating a new user.\n\n### Step 3: Testing the Hashed Password\n\nAfter implementing the changes, you can test the registration functionality again using Postman, as you did in Day 6. This time, when you check the user data in MongoDB Atlas or Compass, you should see the password field containing a hashed value instead of the plain text password.\n\n#### Screenshot Reference:\n\n- **Hashed Password in Database**:\n  - ![Hashed Password](./screenshots/hashedPassword.png)\n\n### Conclusion:\n\nBy hashing passwords before storing them, you've taken an essential step toward securing user data in your application. Bcrypt.js is a widely-used and trusted library for password hashing, making it an excellent choice for this task.\n\n## Day 8 - Secure User Authentication with JSON Web Token (JWT)\n\nJSON Web Tokens (JWT) are an open standard (RFC 7519) that defines a compact and self-contained way of securely transmitting information between parties as a JSON object. JWTs are widely used for authentication and authorization in web applications.\n\n### Why Use JWT?\n\n1. **Authentication**: JWTs help verify the identity of a user or a client.\n2. **Authorization**: JWTs determine what actions a user or client is allowed to perform.\n\n### Components of a JWT\n\n- **Header**: Contains metadata about the token, such as the type of token and the signing algorithm being used.\n- **Payload**: Contains claims or statements about an entity (typically the user) and additional data. Common claims include user ID, username, and expiration time.\n- **Signature**: Ensures that the sender of the JWT is who they claim to be and that the message has not been altered.\n\n### Important Note:\n\nTokens like JWTs are typically not stored in the database along with other user details. Instead, they are issued by the server during the authentication process and then stored on the client side (e.g., in cookies or local storage) for later use.\n\n### Step 1: Install JWT\n\nTo start using JWT, install the `jsonwebtoken` package:\n\n```bash\nnpm i jsonwebtoken\n```\n\n### Step 2: Modify `auth-controller.js` to Generate JWT\n\nNow, update the `auth-controller.js` file to generate and send a JWT when a user registers:\n\n```js\nconst User = require(\"../models/user-model\");\nconst bcrypt = require(\"bcryptjs\");\n\nconst register = async (req, res) =\u003e {\n  try {\n    const { username, email, phone, password } = req.body;\n\n    if (!username || !email || !phone || !password) {\n      return res.status(400).json({ message: \"Please fill all the fields\" });\n    }\n\n    const userExists = await User.findOne({ email: email });\n    if (userExists) {\n      return res.status(400).json({ message: \"User already exists\" });\n    }\n\n    const saltRounds = 10;\n    const hashedPassword = await bcrypt.hash(String(password), saltRounds);\n\n    // Create a new user\n    const user = await User.create({\n      username,\n      email,\n      phone,\n      password: hashedPassword,\n    });\n\n    // Generate JWT Token\n    const token = await user.generateToken();\n\n    res.status(201).json({\n      message: \"User registered successfully\",\n      createdUser: user,\n      token: token,\n      userId: user._id.toString(),\n    });\n  } catch (error) {\n    console.error(error);\n    res.status(500).json({ message: \"Server error\" });\n  }\n};\n\nmodule.exports = { register };\n```\n\n### Step 3: Add `generateToken` Method in `user-model.js`\n\nNext, head over to `user-model.js` and add a method to generate a JWT:\n\n```js\nconst mongoose = require(\"mongoose\");\nconst jwt = require(\"jsonwebtoken\");\n\nconst userSchema = new mongoose.Schema({\n  username: { type: String, required: true },\n  email: { type: String, required: true, unique: true },\n  phone: { type: Number, required: true },\n  password: { type: String, required: true },\n  isAdmin: { type: Boolean, default: false },\n});\n\nuserSchema.methods.generateToken = function () {\n  try {\n    const token = jwt.sign(\n      { _id: this._id, email: this.email, isAdmin: this.isAdmin },\n      process.env.JWT_SECRET,\n      { expiresIn: \"7d\" }\n    );\n    return token;\n  } catch (error) {\n    console.error(error);\n    return null;\n  }\n};\n\nconst User = mongoose.model(\"User\", userSchema);\nmodule.exports = User;\n```\n\n### Step 4: Add JWT Secret Key to `.env` File\n\nFinally, add your JWT secret key to your `.env` file:\n\n```bash\nJWT_SECRET=your_secret_key\n```\n\nNote : A **secret key** is a unique string used to sign and verify JWTs, ensuring their authenticity and integrity. It protects against unauthorized access by allowing the server to confirm that the token hasn't been tampered with.\n\n### Step 5: Testing JWT in Postman\n\nAfter these changes, you can register a user via Postman. The response should include a JWT token, which you can use for authentication in future requests.\n\n#### Screenshot Reference:\n\n- **JWT Token in Postman**:\n  - ![JWT Token](./screenshots/jwt.png)\n\n### Conclusion:\n\nBy using JSON Web Tokens (JWT), you've added an extra layer of security to your user authentication process. JWTs are an effective and scalable solution for managing user sessions in modern web applications.\n\n## Day 9 - User Login Route\n\nTo implement user login functionality, add the following route in `auth-router.js`:\n\n```js\nrouter.route(\"/login\").post(login);\n```\n\nIn `auth-controller.js`, define the `login` function:\n\n```js\nconst login = async (req, res) =\u003e {\n  try {\n    const { email, password } = req.body;\n\n    // Check if any field is empty\n    if (!email || !password) {\n      return res.status(400).json({ message: \"Please fill all the fields\" });\n    }\n\n    // Check if the user exists\n    const user = await User.findOne({ email });\n    if (!user) {\n      return res.status(400).json({ message: \"Invalid Credentials\" });\n    }\n\n    // Compare the password\n    const isPasswordValid = await bcrypt.compare(\n      String(password),\n      user.password\n    );\n    if (!isPasswordValid) {\n      return res\n        .status(401)\n        .json({ message: \"Username or Password is Incorrect\" });\n    }\n\n    // Successful login, return JWT\n    res.status(200).json({\n      message: \"User logged in successfully\",\n      token: await user.generateToken(),\n      userId: user._id.toString(),\n    });\n  } catch (error) {\n    console.error(error);\n    res.status(500).json({ message: \"Server error. Please try again later.\" });\n  }\n};\n\nmodule.exports = { home, register, login };\n```\n\n### Screenshot of the Login Route in Postman\n\n- ![Login](./screenshots/login_route.png)\n\n## Day 10 - Validation using Zod\n\nToday, we’re focusing on implementing validation using **Zod**, a TypeScript-first schema declaration and validation library. Zod is designed to provide an easy-to-use and powerful way to validate data in JavaScript and TypeScript projects. It allows you to define schemas for your data and validate them with a simple API.\n\n### What is Zod?\n\nZod is a schema validation library that provides a type-safe way to validate and parse data. It supports a wide range of validation features, including string, number, array, object validation, and more. Zod is particularly useful when you want to ensure that data conforms to a specific structure or set of rules, making it ideal for validating request bodies, query parameters, and other inputs in your applications.\n\n### How Zod Works\n\n1. **Define Schemas**: You define schemas that describe the expected shape and constraints of your data.\n2. **Parse and Validate**: You use these schemas to parse and validate incoming data. If the data does not meet the schema’s requirements, Zod throws a detailed error.\n3. **Handle Errors**: You catch and handle validation errors to provide meaningful feedback to users.\n\n### Steps to Implement Validation\n\n#### 1. Install Zod\n\nFirst, install Zod in your project:\n\n```bash\nnpm i zod\n```\n\n#### 2. Create Validator Schema\n\nCreate a folder named `validator` in the backend directory. Inside this folder, create a file named `auth-validator.js` with the following content:\n\n```js\nconst { z } = require(\"zod\");\n\nconst SignUpSchema = z.object({\n  username: z\n    .string({ required_error: \"Username is required\" })\n    .trim()\n    .min(3, { message: \"Username must be at least 3 characters long\" })\n    .max(255, { message: \"Username must be at most 255 characters long\" }),\n\n  email: z\n    .string({ required_error: \"Email is required\" })\n    .trim()\n    .min(3, { message: \"Email must be at least 3 characters long\" })\n    .max(255, { message: \"Email must be at most 255 characters long\" })\n    .email({ message: \"Invalid email address\", tldWhitelist: [\"com\", \"net\"] }),\n\n  phone: z\n    .string({ required_error: \"Phone is required\" })\n    .trim()\n    .min(10, { message: \"Phone must be at least 10 characters long\" })\n    .max(15, { message: \"Phone must be at most 15 characters long\" })\n    .regex(/^\\d+$/, { message: \"Phone must contain only digits\" }),\n\n  password: z\n    .string({ required_error: \"Password is required\" })\n    .min(6, { message: \"Password must be at least 6 characters long\" })\n    .max(255, { message: \"Password must be at most 255 characters long\" }),\n});\n\nmodule.exports = { SignUpSchema };\n```\n\n#### 3. Create Validation Middleware\n\nCreate a folder named `middlewares` and add a file named `validate-middleware.js`:\n\n```js\nconst validate = (Schema) =\u003e async (req, res, next) =\u003e {\n  try {\n    const parsedBody = Schema.parse(req.body); // Validate the request body\n    req.body = parsedBody; // Overwrite the request body with the parsed data\n    next(); // Move to the next middleware or route handler\n  } catch (error) {\n    res.status(400).json({\n      message: \"Validation Failed\",\n      errors: error.errors, // Detailed errors from Zod\n    });\n  }\n};\n\nmodule.exports = validate;\n```\n\n#### 4. Update Routes\n\nIntegrate the validation middleware into your routes. Open `auth-router.js` and update it as follows:\n\n```js\nconst express = require(\"express\");\nconst router = express.Router();\nconst { home, register, login } = require(\"../controllers/auth-controller\");\nconst { SignUpSchema } = require(\"../validators/auth-validator\");\nconst validate = require(\"../middlewares/validate-middleware\");\n\nrouter.route(\"/\").get(home);\n\nrouter.route(\"/register\").post(validate(SignUpSchema), register); // Add validation middleware here\n\nrouter.route(\"/login\").post(login);\n\nmodule.exports = router;\n```\n\n#### Zod Validation Errors in Postman\n\n![zod validation errors in postman](./screenshots/zod.png)\n\n### Summary\n\nBy following these steps, you’ve integrated Zod validation into your Express application. This setup ensures that incoming data is validated according to the defined schema, providing robust error handling and improving data integrity in your application.\n\n## Day 11 - Express Error Handling Middleware\n\nToday’s focus was on implementing centralized error handling in an Express.js application using a custom error middleware. This approach allows you to manage all errors from a single place, enhancing code maintainability and readability.\n\n### Key Concepts\n\n- **Error Middleware:** A special type of middleware in Express that handles errors thrown in the application, simplifying error management.\n- **Centralized Error Handling:** Allows catching and responding to errors from a single location, improving maintainability.\n\n### Implementation Steps\n\n1. **Create the Error Middleware:**\n\n   In the `middlewares` folder, create a file named `error-middleware.js`:\n\n   ```js\n   const errorMiddleware = (err, req, res, next) =\u003e {\n     const status = err.status || 500;\n     const message =\n       err.message ||\n       \"Something went wrong. Server error. Please try again later.\";\n     return res.status(status).json({ message });\n   };\n\n   module.exports = errorMiddleware;\n   ```\n\n2. **Modify Your Controllers:**\n\n   Replace `catch` blocks with `next(error)` to delegate error handling to the middleware. For example, in `auth-controller.js`:\n\n   ```js\n   const register = async (req, res, next) =\u003e {\n     try {\n       const { username, email, phone, password } = req.body;\n\n       if (!username || !email || !phone || !password) {\n         return res.status(400).json({ message: \"Please fill all the fields\" });\n       }\n\n       const userExists = await User.findOne({ email });\n       if (userExists) {\n         return res.status(400).json({ message: \"User already exists\" });\n       }\n\n       const saltRound = 10;\n       const hashedPassword = await bcrypt.hash(String(password), saltRound);\n\n       const user = await User.create({\n         username,\n         email,\n         phone,\n         password: hashedPassword,\n       });\n\n       res.status(201).json({\n         message: \"User registered successfully\",\n         createdUser: user,\n         token: await user.generateToken(),\n         userId: user._id.toString(),\n       });\n     } catch (error) {\n       next(error); // Pass the error to the middleware\n     }\n   };\n   ```\n\n3. **Update the Validate Middleware:**\n\n   Update the validation middleware to send errors to the error middleware:\n\n   ```js\n   const validate = (Schema) =\u003e async (req, res, next) =\u003e {\n     try {\n       const parsedBody = Schema.parse(req.body);\n       req.body = parsedBody;\n       next();\n     } catch (error) {\n       next({\n         status: 400,\n         message: error.errors,\n       });\n     }\n   };\n\n   module.exports = validate;\n   ```\n\n4. **Integrate the Middleware:**\n\n   Finally, make sure to include the error middleware in `index.js`:\n\n   ```js\n   require(\"dotenv\").config();\n   const express = require(\"express\");\n   const app = express();\n   const router = require(\"./router/auth-router\");\n   const connectDB = require(\"./utils/db\");\n   const errorMiddleware = require(\"./middlewares/error-middleware\");\n\n   app.use(express.json());\n   app.use(\"/api/auth\", router);\n\n   app.get(\"/\", (req, res) =\u003e {\n     res.send(\"Hello World\");\n   });\n\n   app.use(errorMiddleware); // This must be just above the connection\n\n   connectDB()\n     .then(() =\u003e {\n       const PORT = process.env.PORT || 3000;\n       app.listen(PORT, () =\u003e {\n         console.log(`Server is running on port ${PORT}`);\n       });\n     })\n     .catch((err) =\u003e {\n       console.error(\"Database connection failed\", err);\n       process.exit(1);\n     });\n   ```\n\n### Summary\n\nBy setting up a centralized error handling middleware in Express, you can efficiently manage errors across your application, improving the reliability and readability of your code.\n\n## Day 12 - Contact Form (Schema, Route \u0026 Logics)\n\nToday’s focus was on implementing a contact form in an Express.js application. This included creating a Mongoose schema, setting up routes, and defining the logic for handling form submissions.\n\n### Key Concepts\n\n- **Mongoose Schema:** Defines the structure of the data for MongoDB.\n- **Express Routes:** Handles incoming requests and integrates with controllers.\n- **Error Handling:** Manages and logs errors during form submission.\n\n### Implementation Steps\n\n#### 1. Define the Mongoose Schema\n\nCreate a schema for the contact form data in `models/contact-form-model.js`:\n\n```js\nconst mongoose = require(\"mongoose\");\n\nconst contactFormSchema = new mongoose.Schema({\n  email: {\n    type: String,\n    required: true,\n  },\n  subject: {\n    type: String,\n    required: true,\n  },\n  message: {\n    type: String,\n    required: true,\n  },\n});\n\nconst ContactForm = mongoose.model(\"ContactForm\", contactFormSchema);\nmodule.exports = ContactForm;\n```\n\n**Note:** Ensure that the `email` field is not unique if you want to allow multiple submissions with the same email address.\n\n#### 2. Create the Contact Form Controller\n\nImplement the logic to handle form submissions in `controllers/contact-controller.js`:\n\n```js\nconst Contact = require(\"../models/contact-form-model\");\n\nconst contactForm = async (req, res, next) =\u003e {\n  try {\n    console.log(req.body);\n\n    const { email, subject, message } = req.body;\n\n    // Check if any field is empty\n    if (!email || !subject || !message) {\n      return res.status(400).json({ message: \"Please fill all the fields\" });\n    }\n\n    // Create a new form data\n    const contactData = await Contact.create({\n      email,\n      subject,\n      message,\n    });\n\n    res.status(201).json({\n      message: \"Form Submitted Successfully\",\n      formData: contactData,\n    });\n\n    console.log(contactData);\n  } catch (error) {\n    console.error(error);\n    next(error); // Pass the error to the middleware\n  }\n};\n\nmodule.exports = { contactForm };\n```\n\n#### 3. Set Up the Route\n\nDefine the route to handle contact form submissions in `router/contact-router.js`:\n\n```js\nconst express = require(\"express\");\nconst router = express.Router();\nconst { contactForm } = require(\"../controllers/contact-controller\");\nconst { ContactFormSchema } = require(\"../validators/contact-form-validator\");\nconst validate = require(\"../middlewares/validate-middleware\");\n\nrouter.route(\"/contact\").post(validate(ContactFormSchema), contactForm); // Middleware to validate the request body\n\nmodule.exports = router;\n```\n\n#### 4. Create Validation Schema\n\nImplement the validation logic for the contact form data in `validators/contact-form-validator.js`:\n\n```js\nconst { z } = require(\"zod\");\n\nconst ContactFormSchema = z.object({\n  email: z\n    .string({ required_error: \"Email is required\" })\n    .trim()\n    .min(3, { message: \"Email must be at least 3 characters long\" })\n    .max(255, { message: \"Email must be at most 255 characters long\" })\n    .email({ message: \"Invalid email address\", tldWhitelist: [\"com\", \"net\"] }),\n\n  subject: z\n    .string({ required_error: \"Subject is required\" })\n    .trim()\n    .min(3, { message: \"Subject must be at least 3 characters long\" })\n    .max(255, { message: \"Subject must be at most 255 characters long\" }),\n\n  message: z\n    .string({ required_error: \"Message is required\" })\n    .trim()\n    .min(3, { message: \"Message must be at least 3 characters long\" })\n    .max(255, { message: \"Message must be at most 255 characters long\" }),\n});\n\nmodule.exports = { ContactFormSchema };\n```\n\n#### 5. Update Main Application File\n\nEnsure the contact route is integrated into your main application file `index.js`:\n\n```js\nrequire(\"dotenv\").config();\nconst express = require(\"express\");\nconst app = express();\nconst authRoute = require(\"./router/auth-router\");\nconst contactRoute = require(\"./router/contact-router\");\nconst connectDB = require(\"./utils/db\");\nconst errorMiddleware = require(\"./middlewares/error-middleware\");\n\n// Middleware\napp.use(express.json());\napp.use(\"/api/auth\", authRoute);\napp.use(\"/api/form\", contactRoute);\n\napp.get(\"/\", (req, res) =\u003e {\n  res.send(\"Hello World\");\n});\n\napp.use(errorMiddleware); // This must be just above the connection\n\n// Connect to the database and start the server\nconnectDB()\n  .then(() =\u003e {\n    const PORT = process.env.PORT || 3000;\n    app.listen(PORT, () =\u003e {\n      console.log(`Server is running on port ${PORT}`);\n    });\n  })\n  .catch((err) =\u003e {\n    console.error(\"Database connection failed\", err);\n    process.exit(1);\n  });\n```\n\n### Testing\n\nTo test the contact form, use Postman to send a POST request to `http://localhost:3000/api/form/contact` with the following JSON body:\n\n```json\n{\n  \"email\": \"example@example.com\",\n  \"subject\": \"Test Subject\",\n  \"message\": \"This is a test message.\"\n}\n```\n\n- For visual reference, check the screenshots provided:\n\n- ![Contact Form Testing Postman](./screenshots/contactFormPostman.png)\n\n### Summary\n\nIn this setup, we created a contact form feature that includes a Mongoose schema, an Express route, and validation logic. The contact form allows users to submit their email, subject, and message, and the data is stored in MongoDB.\n\nThis centralized approach to handling form submissions, including validation and error management, helps maintain clean and organized code.\n\n## Day 13 - Installing ReactJS\n\n### Step 1: Set Up the ReactJS Project\n\n1. **Navigate to the frontend directory**:\n\n   ```bash\n   cd frontend\n   ```\n\n2. **Create a new React project using Vite**:\n\n   ```bash\n   npm create vite@latest .\n   ```\n\n3. **Configuration**:\n\n   - Select a framework: **React**\n   - Select a variant: **JavaScript**\n\n4. **Install dependencies and start the development server**:\n   ```bash\n   npm install\n   npm run dev\n   ```\n\n### Step 2: Install and Configure Tailwind CSS\n\n1. **Install Tailwind CSS and its dependencies**:\n\n   ```bash\n   npm install -D tailwindcss postcss autoprefixer\n   npx tailwindcss init -p\n   ```\n\n2. **Configure Tailwind in `tailwind.config.js`**:\n\n   ```js\n   /** @type {import('tailwindcss').Config} */\n   export default {\n     content: [\"./index.html\", \"./src/**/*.{js,ts,jsx,tsx}\"],\n     theme: {\n       extend: {},\n     },\n     plugins: [],\n   };\n   ```\n\n3. **Update `index.css` to use Tailwind’s base, components, and utilities**:\n   ```css\n   @tailwind base;\n   @tailwind components;\n   @tailwind utilities;\n   ```\n\n### Step 3: Test Tailwind CSS Installation\n\n1. **Update `App.jsx` to include a test component**:\n\n   ```jsx\n   import \"./App.css\";\n\n   const App = () =\u003e {\n     return (\n       \u003c\u003e\n         \u003ch1 className=\"text-3xl font-bold underline\"\u003eHello world!\u003c/h1\u003e\n       \u003c/\u003e\n     );\n   };\n\n   export default App;\n   ```\n\n2. **Run the development server to verify the setup**:\n   ```bash\n   npm run dev\n   ```\n\nAfter following these steps, you should see \"Hello world!\" styled with Tailwind CSS on your browser, indicating that your ReactJS environment is successfully set up.\n\n## Day 14 - Page Navigation with React Router DOM\n\nToday, we're learning how to create a multi-page application in React using **React Router DOM**. This will allow us to navigate between different pages without reloading the browser.\n\n### What You’ll Learn\n\n- **React Router DOM basics**: How to set up and use React Router for page navigation.\n- **Creating a simple layout**: Adding a Header, Footer, and dynamic content area.\n- **Routing in React**: Displaying different components based on the URL path.\n\nLet’s break it down step by step!\n\n### Step 1: Installing React Router DOM\n\nFirst, we need to install `react-router-dom`, a package that handles routing in React applications.\n\n#### Installation Command\n\nOpen your terminal and run:\n\n```bash\nnpm install react-router-dom\n```\n\nThis command installs the necessary library, enabling us to set up navigation between different pages in our React app.\n\n### Step 2: Creating Page Components\n\nWe'll create three simple pages: Home, About, and Contact. These will be the different pages that users can navigate to.\n\n#### Folder Structure\n\n1. Inside the `src` directory, create a new folder named `pages`.\n2. In the `pages` folder, create three files: `Home.jsx`, `About.jsx`, and `Contact.jsx`.\n\n#### Writing Page Components\n\n**Home.jsx:**\n\n```jsx\nconst Home = () =\u003e {\n  return (\n    \u003cdiv\u003e\n      \u003ch1 className=\"m-3\"\u003eHome Page\u003c/h1\u003e\n    \u003c/div\u003e\n  );\n};\n\nexport default Home;\n```\n\n**About.jsx:**\n\n```jsx\nconst About = () =\u003e {\n  return (\n    \u003cdiv\u003e\n      \u003ch1 className=\"m-3\"\u003eAbout Page\u003c/h1\u003e\n    \u003c/div\u003e\n  );\n};\n\nexport default About;\n```\n\n**Contact.jsx:**\n\n```jsx\nconst Contact = () =\u003e {\n  return (\n    \u003cdiv\u003e\n      \u003ch1 className=\"m-3\"\u003eContact Page\u003c/h1\u003e\n    \u003c/div\u003e\n  );\n};\n\nexport default Contact;\n```\n\n#### Explanation:\n\n- Each file contains a simple functional component. A functional component is just a JavaScript function that returns some JSX (HTML-like syntax).\n- We’re keeping the pages simple with just a heading for now. The goal is to understand routing.\n\n### Step 3: Creating Header and Footer Components\n\nNow, let’s create a navigation menu (Header) and a Footer that will appear on every page.\n\n#### Folder Structure\n\n1. Inside the `src` directory, create another folder named `components`.\n2. In the `components` folder, create two files: `Header.jsx` and `Footer.jsx`.\n\n#### Writing Header and Footer Components\n\n**Header.jsx:**\n\n```jsx\n// Importing NavLink from React Router to create navigation links\nimport { NavLink } from \"react-router-dom\";\n\nconst Header = () =\u003e {\n  return (\n    \u003cheader className=\"w-full\"\u003e\n      \u003cnav className=\"bg-white text-lg\"\u003e\n        \u003cul className=\"flex font-medium\"\u003e\n          \u003cli className=\"m-3\"\u003e\n            \u003cNavLink\n              to=\"/\"\n              className={({ isActive }) =\u003e\n                `py-2 ${isActive ? \"text-orange-700\" : \"text-gray-700\"}`\n              }\n            \u003e\n              Home\n            \u003c/NavLink\u003e\n          \u003c/li\u003e\n          \u003cli className=\"m-3\"\u003e\n            \u003cNavLink\n              to=\"/about\"\n              className={({ isActive }) =\u003e\n                `py-2 ${isActive ? \"text-orange-700\" : \"text-gray-700\"}`\n              }\n            \u003e\n              About\n            \u003c/NavLink\u003e\n          \u003c/li\u003e\n          \u003cli className=\"m-3\"\u003e\n            \u003cNavLink\n              to=\"/contact\"\n              className={({ isActive }) =\u003e\n                `py-2 ${isActive ? \"text-orange-700\" : \"text-gray-700\"}`\n              }\n            \u003e\n              Contact\n            \u003c/NavLink\u003e\n          \u003c/li\u003e\n        \u003c/ul\u003e\n      \u003c/nav\u003e\n    \u003c/header\u003e\n  );\n};\n\nexport default Header;\n```\n\n#### Explanation:\n\n- **NavLink:** This component works like an anchor (`\u003ca\u003e`) tag but with additional features from React Router. It helps you create navigation links that are aware of the active route.\n- **Dynamic Styling:** The function inside `className` checks if the link is active. If it is, the link text turns orange; otherwise, it remains gray.\n\n**Footer.jsx:**\n\n```jsx\nconst Footer = () =\u003e {\n  return \u003cdiv className=\"m-3\"\u003eFooter\u003c/div\u003e;\n};\n\nexport default Footer;\n```\n\nThe `Footer.jsx` component is simple and straightforward, just displaying a footer message.\n\n### Step 4: Setting Up the Main Application Layout\n\nThe `App.jsx` file will act as our main layout. It will include the Header, Footer, and a dynamic content area where different pages will be displayed.\n\n#### Updating `App.jsx`\n\nReplace the existing content in `App.jsx` with the following:\n\n```jsx\n// Importing outlet\nimport { Outlet } from \"react-router-dom\";\nimport Header from \"./components/Header\";\nimport Footer from \"./components/Footer\";\nimport \"./App.css\";\n\nconst App = () =\u003e {\n  return (\n    \u003c\u003e\n      {/* Header at the top of every page */}\n      \u003cHeader /\u003e\n      {/* Outlet to render the current page */}\n      \u003cOutlet /\u003e\n      {/* Footer at the bottom of every page */}\n      \u003cFooter /\u003e\n    \u003c/\u003e\n  );\n};\n\nexport default App;\n```\n\n#### Explanation:\n\n- **Header \u0026 Footer:** These components are included so they appear on every page.\n- **Outlet:** This is a placeholder where the current page content (like Home, About, or Contact) will be displayed based on the active route.\n\n### Step 5: Defining Routes in `main.jsx`\n\nNow, let’s set up our routes to connect the URLs with the pages we’ve created.\n\n#### Updating `main.jsx`\n\nReplace the existing content in `main.jsx` with the following:\n\n```jsx\nimport { StrictMode } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport App from \"./App.jsx\";\nimport \"./index.css\";\n\n// Import necessary modules\nimport {\n  Route,\n  RouterProvider,\n  createBrowserRouter,\n  createRoutesFromElements,\n} from \"react-router-dom\";\n\nimport Home from \"./pages/Home.jsx\";\nimport About from \"./pages/About.jsx\";\nimport Contact from \"./pages/Contact.jsx\";\n\n// Define the routes for the application\nconst router = createBrowserRouter(\n  createRoutesFromElements(\n    \u003cRoute path=\"/\" element={\u003cApp /\u003e}\u003e\n      {/* Home route */}\n      \u003cRoute path=\"\" element={\u003cHome /\u003e} /\u003e\n      {/* About route */}\n      \u003cRoute path=\"/about\" element={\u003cAbout /\u003e} /\u003e\n      {/* Contact route */}\n      \u003cRoute path=\"/contact\" element={\u003cContact /\u003e} /\u003e\n    \u003c/Route\u003e\n  )\n);\n\ncreateRoot(document.getElementById(\"root\")).render(\n  \u003cStrictMode\u003e\n    {/* Provide the router configuration to the application */}\n    \u003cRouterProvider router={router} /\u003e\n  \u003c/StrictMode\u003e\n);\n```\n\n#### Explanation:\n\n- **Route Configuration:** The `Route` component connects each URL path to a specific component. For example, when the user navigates to `/about`, the `About` component is displayed.\n- **Nested Routes:** The `App` component serves as a parent route, so `Header` and `Footer` are always shown, and the `Outlet` dynamically loads the current page based on the route.\n\n### Step 6: Testing the Application\n\nNow that everything is set up, let’s test it out!\n\n#### Running the Application\n\n1. **Start the Development Server:**\n\n   ```bash\n   npm run dev\n   ```\n\n   This command starts the React development server.\n\n2. **Open the Browser:**\n\n   - Navigate to `http://localhost:3000/` in your web browser. You should see the Home page.\n\n3. **Navigate Between Pages:**\n   - Click on the \"About\" link in the Header to navigate to the About page.\n   - Click on the \"Contact\" link to navigate to the Contact page.\n   - Notice how the URL changes, but the page doesn’t reload—this is the magic of React Router!\n\n### Recap \u0026 Conclusion\n\nWell done! 🎉 You’ve successfully created a multi-page React application with seamless navigation. Here's a quick recap of what you learned today:\n\n- **React Router DOM Basics:** You learned how to install and set up routing in a React app.\n- **Creating a Layout:** You built a consistent layout with a Header and Footer across all pages.\n- **Dynamic Navigation:** You used `NavLink` to highlight the current page and make navigation intuitive.\n\nThis knowledge is crucial for building real-world React applications. Keep experimenting with routing, and soon you'll be building even more dynamic and complex apps! 🚀\n\nFor more knowledge about React Router DOM, do checkout this repo : [React Router Crash Course](https://github.com/AmanKumarSinhaGitHub/React-Router-Crash-Course)\n\n## Day 15 - Registration Form in React JS\n\nIn this lesson, we'll build a simple registration form in React JS and add navigation for the form. This tutorial will guide you step-by-step, making sure that even if you’re new to React, you’ll understand each part clearly.\n\n### Step 1: Adding a NavLink for the Registration Page\n\nWe start by adding a new navigation link that points to our registration page. This will allow users to easily navigate to the registration form from the website's header.\n\n#### Update `Header.jsx`\n\nAdd a new NavLink for the `/register` page:\n\n```jsx\n\u003cNavLink\n  to=\"/register\"\n  className={({ isActive }) =\u003e\n    `py-2 ${isActive ? \"text-blue-400\" : \"text-gray-300\"} hover:text-blue-400`\n  }\n\u003e\n  Register\n\u003c/NavLink\u003e\n```\n\n#### Explanation:\n\n- **`NavLink` Component:** Used to create navigation links in React. The `to` prop specifies the URL path, and the `className` applies styles dynamically based on whether the link is active.\n- **Dynamic Styling:** The `className` uses `isActive` to highlight the link when the user is on the corresponding page.\n\n### Step 2: Adding a Route for the Registration Page\n\nNext, we need to define a route for our new registration page so that React Router knows what to display when the user navigates to `/register`.\n\n#### Update `main.jsx`\n\nAdd the route for the registration page:\n\n```jsx\nconst router = createBrowserRouter(\n  createRoutesFromElements(\n    \u003cRoute path=\"/\" element={\u003cApp /\u003e}\u003e\n      \u003cRoute path=\"\" element={\u003cHome /\u003e} /\u003e\n      \u003cRoute path=\"/about\" element={\u003cAbout /\u003e} /\u003e\n      \u003cRoute path=\"/contact\" element={\u003cContact /\u003e} /\u003e\n      \u003cRoute path=\"/register\" element={\u003cRegister /\u003e} /\u003e {/* Route for Register Page */}\n    \u003c/Route\u003e\n  )\n);\n```\n\n#### Explanation:\n\n- **Route Setup:** We’re telling React Router to render the `Register` component when the user visits `/register`.\n\n### Step 3: Creating the Registration Page Component\n\nLet’s now create the registration page component. This component will contain a form where users can input their details like username, email, phone number, and password.\n\n#### Create `Register.jsx`\n\nInside the `pages` folder, create a new file named `Register.jsx`:\n\n```jsx\nimport { useState } from \"react\";\n\nconst Register = () =\u003e {\n  // State to manage form data\n  const [formData, setFormData] = useState({\n    username: \"\",\n    email: \"\",\n    phone: \"\",\n    password: \"\",\n  });\n\n  // Handle input changes\n  const handleInput = (e) =\u003e {\n    const name = e.target.name; // Name of the input field\n    const value = e.target.value; // Value of the input field\n\n    // Update the formData state\n    setFormData({\n      ...formData,\n      [name]: value,\n    });\n  };\n\n  // Handle form submission\n  const handleSubmit = (e) =\u003e {\n    e.preventDefault(); // Prevent default form submission behavior\n    console.log(\"Form submitted:\", formData);\n    // Here we will write logic to store data in backend\n  };\n\n  return (\n    \u003c\u003e\n      \u003cform onSubmit={handleSubmit}\u003e\n        \u003cdiv\u003e\n          \u003clabel htmlFor=\"username\"\u003eUsername\u003c/label\u003e\n          \u003cinput\n            type=\"text\"\n            name=\"username\" // Field identifier\n            id=\"username\"\n            value={formData.username} // State value\n            onChange={handleInput} // Update value\n            placeholder=\"Enter Username\"\n            required\n          /\u003e\n        \u003c/div\u003e\n\n        \u003cdiv\u003e\n          \u003clabel htmlFor=\"email\"\u003eEmail\u003c/label\u003e\n          \u003cinput\n            type=\"email\"\n            name=\"email\"\n            id=\"email\"\n            value={formData.email}\n            onChange={handleInput}\n            placeholder=\"Enter Email\"\n            required\n          /\u003e\n        \u003c/div\u003e\n\n        \u003cdiv\u003e\n          \u003clabel htmlFor=\"phone\"\u003ePhone\u003c/label\u003e\n          \u003cinput\n            type=\"text\"\n            name=\"phone\"\n            id=\"phone\"\n            value={formData.phone}\n            onChange={handleInput}\n            placeholder=\"Enter Phone\"\n            required\n          /\u003e\n        \u003c/div\u003e\n\n        \u003cdiv\u003e\n          \u003clabel htmlFor=\"password\"\u003ePassword\u003c/label\u003e\n          \u003cinput\n            type=\"password\"\n            name=\"password\"\n            id=\"password\"\n            value={formData.password}\n            onChange={handleInput}\n            placeholder=\"Enter Password\"\n            required\n          /\u003e\n        \u003c/div\u003e\n\n        \u003cdiv\u003e\n          \u003cbutton type=\"submit\"\u003eRegister\u003c/button\u003e\n        \u003c/div\u003e\n      \u003c/form\u003e\n    \u003c/\u003e\n  );\n};\n\nexport default Register;\n```\n\n#### Explanation:\n\n- **State Management with `useState`:** We use the `useState` hook to manage the form data, including the username, email, phone number, and password.\n- **Input Handling:** The `handleInput` function captures changes to the input fields and updates the state accordingly.\n- **Form Submission:** The `handleSubmit` function prevents the default form submission behavior and logs the form data to the console. In a real application, you’d replace this with logic to send the data to a backend server.\n\n### Step 4: Creating the Login Page and Contact Us Page (Do It Yourself)\n\nYou’ve successfully created a registration form! Now, as a challenge, try creating a login form on your own. Here’s what you need to do:\n\n1. Add a NavLink for `/login` in `Header.jsx`.\n2. Create a `Login.jsx` component with form fields for email and password.\n3. Add a route for `/login` in `main.jsx`.\n\n**Reference Design**\n\n- ![Register](./screenshots/register.png)\n- ![Login](./screenshots/login.png)\n\nThis guide should help you create a fully functional registration form with navigation. With React, once you understand the basic concepts like state management, routing, and component structure, you can build even more complex applications with ease!\n\n## Day 16 - 404 Error Page (Page Not Found)\n\nToday, we are going to implement a basic 404 error page in our React application. This page will be displayed whenever a user tries to access a route that doesn't exist.\n\n### Step 1: Add the 404 Route in `main.jsx`\n\nFirst, we need to handle routes that don't match any of our defined paths by adding a wildcard (`*`) route in `main.jsx`.\n\n```jsx\nimport Error from \"./pages/Error.jsx\"; // Import the Error page\n\nconst router = createBrowserRouter(\n  createRoutesFromElements(\n    \u003cRoute path=\"/\" element={\u003cApp /\u003e}\u003e\n      \u003cRoute path=\"\" element={\u003cHome /\u003e} /\u003e\n      \u003cRoute path=\"/about\" element={\u003cAbout /\u003e} /\u003e\n      \u003cRoute path=\"/contact\" element={\u003cContact /\u003e} /\u003e\n      \u003cRoute path=\"/register\" element={\u003cRegister /\u003e} /\u003e\n      \u003cRoute path=\"/login\" element={\u003cLogin /\u003e} /\u003e\n      \u003cRoute path=\"*\" element={\u003cError /\u003e} /\u003e {/* Catch-all route for 404 */}\n    \u003c/Route\u003e\n  )\n);\n```\n\n### Step 2: Create the `Error.jsx` Component\n\nNext, we'll create a simple `Error.jsx` component in the `pages` folder. This component will display a \"404 Not Found\" message and a link to return to the homepage.\n\n```jsx\nimport { Link } from \"react-router-dom\";\n\nconst Error = () =\u003e {\n  return (\n    \u003c\u003e\n      \u003ch1\u003e404 Not Found\u003c/h1\u003e\n      \u003cp\u003eSorry, the page you're looking for doesn't exist.\u003c/p\u003e\n      \u003cLink to=\"/\"\u003eGo back to the main page\u003c/Link\u003e{\" \"}\n      {/* Link to redirect user to home */}\n    \u003c/\u003e\n  );\n};\n\nexport default Error;\n```\n\n### Explanation:\n\n- **Wildcard Route (`*`)**: The `*` in the route path acts as a catch-all. Any path that doesn't match the defined routes will fall back to this route, triggering the `Error` component.\n\n- **Error Component**: The `Error.jsx` file is a simple functional component that renders a message informing the user that the page was not found and includes a link to return to the homepage.\n\n### Step 3: Test the 404 Page\n\nNow, if you try to access a route in your application that doesn't exist (e.g., `http://localhost:3000/some-random-route`), the 404 error page will be displayed.\n\nThis setup ensures a smooth user experience by guiding users back to a valid part of your application if they land on an incorrect URL.\n\n## Day 17 - Connect Frontend with Backend and Store Registration Data\n\nOn Day 17, we’ll connect our frontend (React) to the backend (Express.js) to store user registration data in MongoDB. We’ll cover setting up the connection, handling CORS errors, and successfully sending data from the frontend to the backend.\n\n### Prerequisites\n\nEnsure you have two terminals open in VS Code:\n\n1. Start the frontend with `npm run dev`.\n2. Start the backend with `nodemon index.js`.\n\n### Overview\n\nIn the previous steps, we tested our backend using Postman to store data in MongoDB. Now, we’ll connect the frontend to the backend to handle the same functionality using a registration form in React.\n\n### Step 0: Set Up Environment Variables\n\n1. **Frontend `.env` File**: In the frontend folder, create a `.env` file to store the backend URL.\n\n   ```bash\n   VITE_BACKEND_URL=http://localhost:3000\n   ```\n\n2. **Backend `.env` File**: In the backend folder, update the `.env` file to include the frontend URL and other environment variables.\n\n   ```bash\n   PORT=3000\n   MONGO_URI=mongodb+srv://\u003cusername\u003e:\u003cpassword\u003e@cluster1.o4g0r.mongodb.net\n   JWT_SECRET=amansecretkey\n   VITE_FRONTEND_URL=http://localhost:5173\n   ```\n\n### Step 1: Modify `Register.jsx`\n\nWe’ll update the `handleSubmit` function in `Register.jsx` to send the registration data to our backend.\n\n```jsx\nimport { useState } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\n\nconst Register = () =\u003e {\n  const [formData, setFormData] = useState({\n    username: \"\",\n    email: \"\",\n    phone: \"\",\n    password: \"\",\n  });\n\n  const handleChange = (e) =\u003e {\n    const { name, value } = e.target;\n    setFormData({\n      ...formData,\n      [name]: value,\n    });\n  };\n\n  const navigate = useNavigate();\n\n  const BACKEND_URL = import.meta.env.VITE_BACKEND_URL; // Getting the backend URL from the .env file\n\n  const handleSubmit = async (e) =\u003e {\n    e.preventDefault();\n    console.log(\"Form submitted:\", formData);\n\n    try {\n      const response = await fetch(`${BACKEND_URL}/api/auth/register`, {\n        method: \"POST\",\n        headers: {\n          \"Content-Type\": \"application/json\",\n        },\n        body: JSON.stringify(formData), // Convert JS object to JSON string\n      });\n      const data = await response.json();\n      console.log(data);\n\n      // Clearing the form after submission\n      if (response.ok) {\n        setFormData({\n          username: \"\",\n          email: \"\",\n          phone: \"\",\n          password: \"\",\n        });\n\n        alert(\"Registration successful\");\n        navigate(\"/login\");\n      } else {\n        alert(\"Registration failed\");\n      }\n    } catch (error) {\n      console.error(\"Error:\", error);\n    }\n  };\n\n  return (\n    \u003cform onSubmit={handleSubmit}\u003e\n      \u003cdiv\u003e\n        \u003clabel htmlFor=\"username\"\u003eUsername\u003c/label\u003e\n        \u003cinput\n          type=\"text\"\n          name=\"username\"\n          id=\"username\"\n          value={formData.username}\n          onChange={handleChange}\n          placeholder=\"Enter Username\"\n          required\n        /\u003e\n      \u003c/div\u003e\n\n      \u003cdiv\u003e\n        \u003clabel htmlFor=\"email\"\u003eEmail\u003c/label\u003e\n        \u003cinput\n          type=\"email\"\n          name=\"email\"\n          id=\"email\"\n          value={formData.email}\n          onChange={handleChange}\n          placeholder=\"Enter Email\"\n          required\n        /\u003e\n      \u003c/div\u003e\n\n      \u003cdiv\u003e\n        \u003clabel htmlFor=\"phone\"\u003ePhone\u003c/label\u003e\n        \u003cinput\n          type=\"text\"\n          name=\"phone\"\n          id=\"phone\"\n          value={formData.phone}\n          onChange={handleChange}\n          placeholder=\"Enter Phone\"\n          required\n        /\u003e\n      \u003c/div\u003e\n\n      \u003cdiv\u003e\n        \u003clabel htmlFor=\"password\"\u003ePassword\u003c/label\u003e\n        \u003cinput\n          type=\"password\"\n          name=\"password\"\n          id=\"password\"\n          value={formData.password}\n          onChange={handleChange}\n          placeholder=\"Enter Password\"\n          required\n        /\u003e\n      \u003c/div\u003e\n\n      \u003cdiv\u003e\n        \u003cbutton type=\"submit\"\u003eRegister\u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/form\u003e\n  );\n};\n\nexport default Register;\n```\n\n### Step 2: Handle CORS Errors\n\nWhen connecting the frontend with the backend, you might encounter a **CORS Policy Error**. This occurs because web browsers restrict cross-origin HTTP requests.\n\n#### Understanding CORS\n\nCORS (Cross-Origin Resource Sharing) is a security feature that allows or restricts web pages from making requests to a different domain. In a MERN stack application, this issue arises when the frontend and backend are hosted on different domains.\n\n### Step 3: Install and Configure CORS\n\nTo resolve the CORS issue, install the CORS package in the backend.\n\n1. **Install CORS**: Ensure you're in the backend directory and run the following command:\n\n   ```bash\n   npm i cors\n   ```\n\n2. **Configure CORS in `index.js`**: Add the following code to your `index.js` file:\n\n   ```js\n   require(\"dotenv\").config();\n   const express = require(\"express\");\n   const cors = require(\"cors\"); // Import cors\n   const app = express();\n   const authRoute = require(\"./router/auth-router\");\n   const contactRoute = require(\"./router/contact-router\");\n   const connectDB = require(\"./utils/db\");\n   const errorMiddleware = require(\"./middlewares/error-middleware\");\n\n   // CORS options for cross-origin requests\n   const corsOptions = {\n     origin: process.env.VITE_FRONTEND_URL, // Frontend URL from .env\n     optionsSuccessStatus: 200,\n     methods: \"GET,HEAD,PUT,PATCH,POST,DELETE\",\n     credentials: true,\n   };\n\n   app.use(cors(corsOptions)); // Use cors with defined options\n\n   app.use(express.json());\n   app.use(\"/api/auth\", authRoute); // Auth routes\n   app.use(\"/api/form\", contactRoute); // Contact form routes\n\n   app.get(\"/\", (req, res) =\u003e {\n     res.send(\"Hello World\");\n   });\n\n   app.use(errorMiddleware); // Use error middleware\n\n   // Connect to the database and start the server\n   connectDB()\n     .then(() =\u003e {\n       const PORT = process.env.PORT || 3000;\n       app.listen(PORT, () =\u003e {\n         console.log(`Server is running on port ${PORT}`);\n       });\n     })\n     .catch((err) =\u003e {\n       console.error(\"Database connection failed\", err);\n       process.exit(1);\n     });\n   ```\n\n### Step 4: Testing the Connection\n\nAfter making the changes, you should be able to register users through the frontend. Here's what to expect:\n\n1. **MERN Register Frontend Form**:\n   ![MERN Register Frontend Form with Console Log Success Message](./screenshots/signup_with_mern.png)\n\n2. **Registered User in MongoDB Compass**:\n   ![Registered User in MongoDB Compass](./screenshots/register_user_in_mongodb_compass.png)\n\n### Step 5: Add a Start Script to `package.json`\n\nTo streamline the process of starting your backend server, add a `start` script to the `package.json` file inside the backend folder.\n\n#### Modify `package.json`\n\nOpen your `package.json` file in the backend folder and add the following `start` script under `\"scripts\"`:\n\n```json\n{\n  \"name\": \"backend\",\n  \"version\": \"1.0.0\",\n  \"description\": \"server\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"start\": \"node index.js\" // Add this line\n  },\n  \"author\": \"aman\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"bcryptjs\": \"^2.4.3\",\n    \"cors\": \"^2.8.5\",\n    \"dotenv\": \"^16.4.5\",\n    \"express\": \"^4.19.2\",\n    \"jsonwebtoken\": \"^9.0.2\",\n    \"mongodb\": \"^6.8.0\",\n    \"mongoose\": \"^8.5.2\",\n    \"zod\": \"^3.23.8\"\n  }\n}\n```\n\n### Step 6: Run Your Backend\n\nNow, you can start your backend server by running the following command:\n\n```bash\nnpm start\n```\n\nThis command will work in both development and production environments.\n\n### Task: Store Contact Form Data in MongoDB\n\nIn addition to storing registration data, extend the functionality to store contact form data in MongoDB. Follow similar steps as you did for the registration form.\n\nBy the end of this task, you should be able to store both registration and contact form data in MongoDB from the frontend.\n\n## Day 18 - Login Through Frontend\n\nOn Day 18, we'll add login functionality to the frontend using React and connect it to the backend for user authentication.\n\n### Prerequisites\n\n- Backend should be running (`nodemon index.js`).\n- Frontend should be running (`npm run dev`).\n\n### Step 1: Ensure Login Route is Set in `main.jsx`\n\nMake sure the login route is added in `main.jsx`:\n\n```jsx\n\u003cRoute path=\"/login\" element={\u003cLogin /\u003e} /\u003e\n```\n\n### Step 2: Implement Login Functionality in `Login.jsx`\n\nFocus on the `handleSubmit` function to send the login request to the backend. Here's the essential code:\n\n```jsx\nimport { useState } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\n\nconst Login = () =\u003e {\n  const [formData, setFormData] = useState({\n    email: \"\",\n    password: \"\",\n  });\n\n  const navigate = useNavigate();\n\n  const handleInput = (e) =\u003e {\n    const name = e.target.name;\n    const value = e.target.value;\n\n    setFormData({\n      ...formData,\n      [name]: value,\n    });\n  };\n\n  const BACKEND_URL = import.meta.env.VITE_BACKEND_URL; // Getting the backend URL(localhost:3000) from the .env file\n\n  const handleSubmit = async (e) =\u003e {\n    e.preventDefault();\n    console.log(\"Form submitted:\", formData);\n\n    try {\n      const response = await fetch(`${BACKEND_URL}/api/auth/login`, {\n        method: \"POST\",\n        headers: {\n          \"Content-Type\": \"application/json\",\n        },\n        body: JSON.stringify(formData),\n      });\n\n      const data = await response.json();\n      console.log(data);\n\n      if (response.ok) {\n        setFormData({ email: \"\", password: \"\" });\n        navigate(\"/\");\n      } else {\n        alert(\"Login failed, please try again.\");\n      }\n    } catch (error) {\n      console.error(\"Error:\", error);\n    }\n  };\n\n  return (\n    \u003cform onSubmit={handleSubmit}\u003e\n      \u003cdiv\u003e\n        \u003clabel htmlFor=\"email\"\u003eEmail\u003c/label\u003e\n        \u003cinput\n          type=\"email\"\n          name=\"email\"\n          id=\"email\"\n          value={formData.email}\n          onChange={handleInput}\n          placeholder=\"Enter Email\"\n          required\n        /\u003e\n      \u003c/div\u003e\n\n      \u003cdiv\u003e\n        \u003clabel htmlFor=\"password\"\u003ePassword\u003c/label\u003e\n        \u003cinput\n          type=\"password\"\n          name=\"password\"\n          id=\"password\"\n          value={formData.password}\n          onChange={handleInput}\n          placeholder=\"Enter Password\"\n          required\n        /\u003e\n      \u003c/div\u003e\n\n      \u003cbutton type=\"submit\"\u003eLogin\u003c/button\u003e\n    \u003c/form\u003e\n  );\n};\n\nexport default Login;\n```\n\n### Step 3: Test the Login Functionality\n\n- **Successful Login**: Redirects to the homepage.\n- **Login Error**: Displays an alert to the user.\n\n### CORS Issues (Handled)\n\nIf you encounter CORS issues, ensure CORS is set up in the backend (handled on Day 17).\n\n### Backend Logic (Handled)\n\nThe backend logic for handling login requests is already implemented.\n\n### Conclusion\n\nYou now have a functional login page that communicates with the backend to authenticate users.\n\n## Day 19 - Storing JWT Token in Local Storage Using Context API\n\nOn Day 19, we'll focus on securely saving a JWT (JSON Web Token) in the browser's local storage to keep users logged in. We'll use React's **Context API** to make it easier to manage authentication across the app.\n\n### What You’ll Do Today:\n\n1. Create an **authentication context** to store the token.\n2. Wrap your app with the context so it can be used anywhere.\n3. Update the **Login** and **Register** pages to store the token after successful login or registration.\n\n#### Step 1: Create Authentication Context (`auth.jsx`)\n\nFirst, we'll create a new **context** to store and access the JWT token.\n\n1. Create a folder called `Store` inside the `src` directory.\n2. Inside the `Store` folder, create a file named `auth.jsx`.\n3. Add the following code:\n\n```jsx\nimport React, { createContext, useContext } from \"react\";\n\n// Step 1: Create a context\nexport const AuthContext = createContext();\n\n// Step 2: Create a provider to share the token\nexport const AuthProvider = ({ children }) =\u003e {\n  const storeTokenInLocalStorage = (serverToken) =\u003e {\n    localStorage.setItem(\"token\", serverToken); // Save the token in local storage\n  };\n\n  return (\n    \u003cAuthContext.Provider value={{ storeTokenInLocalStorage }}\u003e\n      {children} {/* All components inside will have access to this */}\n    \u003c/AuthContext.Provider\u003e\n  );\n};\n\n// Step 3: Create a custom hook to use the context easily\nexport const useAuth = () =\u003e {\n  return useContext(AuthContext);\n};\n```\n\n**Explanation:**\n\n- **Context** allows us to share data (like a token) between components without passing it manually every time.\n- The `AuthProvider` provides the function `storeTokenInLocalStorage` to save the token in local storage.\n- The `useAuth` hook makes it easier to use this function in other parts of the app.\n\n#### Step 2: Wrap Your App with `AuthProvider`\n\nNext, we need to make this authentication context available to the entire app.\n\n1. Open `main.jsx`.\n2. Wrap your app in the `AuthProvider` component, like this:\n\n```jsx\nimport { AuthProvider } from \"./store/auth\";\n\ncreateRoot(document.getElementById(\"root\")).render(\n  \u003cAuthProvider\u003e\n    {\" \"}\n    {/* Wrap the app to give access to the auth context */}\n    \u003cStrictMode\u003e\n      \u003cRouterProvider router={router} /\u003e\n    \u003c/StrictMode\u003e\n  \u003c/AuthProvider\u003e\n);\n```\n\n#### Step 3: Update `Login.jsx` and `Register.jsx` to Save the Token\n\nNow, we’ll update the **Login** and **Register** pages so they can store the token after a successful login or registration.\n\n1. Open `Login.jsx` (and similarly for `Register.jsx`).\n2. Modify the file to save the token when the login/registration is successful:\n\n```jsx\nimport { useAuth } from \"../store/auth\"; // Import the custom hook to access auth context\n\nconst { storeTokenInLocalStorage } = useAuth(); // Get the function to store token\n\nconst data = await response.json(); // Get the response data (which includes the token)\n\nif (response.ok) {\n  storeTokenInLocalStorage(data.token); // Save the token in local storage\n\n  setFormData({\n    email: \"\",\n    password: \"\",\n  });\n\n  alert(\"Login successful\");\n  navigate(\"/\"); // Redirect to the homepage\n} else {\n  alert(\"Login failed, please try again.\");\n}\n```\n\n**What’s Happening Here:**\n\n- After a successful login or registration, the JWT token is returned by the server.\n- We use `storeTokenInLocalStorage(data.token)` to save the token in local storage.\n- This ensures the user stays logged in, even after refreshing the page.\n\n#### Step 4: Check the Token in Local Storage\n\nYou can verify that the JWT token is being stored in the browser by:\n\n1. Opening your app.\n2. Logging in or registering.\n3. Inspecting the browser's local storage (Right-click -\u003e Inspect -\u003e Application tab -\u003e Local Storage).\n\nHere’s how it should look:\n\n![local_storage_token](./screenshots/localStorage_token.png)\n\n#### Summary\n\nAfter completing Day 19:\n\n- You now have a system to save JWT tokens in the browser.\n- The token is stored securely in local storage using the **Context API**.\n- Your app can now keep users logged in across different pages and sessions.\n\nThis process is essential for authentication in modern web apps and will help keep your users logged in securely!\n\n## Day 20 - Logout Functionality\n\nToday, we’ll learn how to log users out of the application by removing the JWT token from local storage. This ensures that when users log out, they are no longer authenticated.\n\n### What You’ll Do Today:\n\n1. Create a **Logout** route in `main.jsx`.\n2. Build a **Logout.jsx** component to handle logging out.\n3. Update the **AuthContext** to include the logout functionality.\n4. Modify the **Header.jsx** to display the **Logout** link when the user is logged in.\n\n### Step 1: Add Logout Route in `main.jsx`\n\nTo start, we need to create a route for logging out.\n\n1. Open `main.jsx`.\n2. Add a new route for the **Logout** page:\n\n```jsx\nconst router = createBrowserRouter(\n  createRoutesFromElements(\n    \u003cRoute path=\"/\" element={\u003cApp /\u003e}\u003e\n      \u003cRoute path=\"\" element={\u003cHome /\u003e} /\u003e\n      \u003cRoute path=\"/about\" element={\u003cAbout /\u003e} /\u003e\n      \u003cRoute path=\"/contact\" element={\u003cContact /\u003e} /\u003e\n      \u003cRoute path=\"/register\" element={\u003cRegister /\u003e} /\u003e\n      \u003cRoute path=\"/login\" element={\u003cLogin /\u003e} /\u003e\n      \u003cRoute path=\"/logout\" element={\u003cLogout /\u003e} /\u003e {/* Logout route */}\n      \u003cRoute path=\"*\" element={\u003cError /\u003e} /\u003e\n    \u003c/Route\u003e\n  )\n);\n```\n\nThis creates a route that points to the **Logout** component.\n\n### Step 2: Create the `Logout.jsx` Component\n\nNext, we’ll create the component that handles logging the user out by clearing the token from local storage.\n\n1. Inside your `pages` folder, create a file called `Logout.jsx`.\n2. Add the following code:\n\n```jsx\nimport { useEffect } from \"react\";\nimport { Navigate } from \"react-router-dom\";\nimport { useAuth } from \"../store/auth\";\n\nconst Logout = () =\u003e {\n  const { LogoutUser } = useAuth(); // Get the logout function from context\n\n  useEffect(() =\u003e {\n    LogoutUser(); // Call logout function when the component loads\n  }, [LogoutUser]);\n\n  return \u003cNavigate to=\"/login\" /\u003e; // Redirect the user to the login page\n};\n\nexport default Logout;\n```\n\n**Explanation:**\n\n- The `LogoutUser` function is called as soon as the component loads, removing the JWT token.\n- After logging out, the user is immediately redirected to the **Login** page.\n\n### Step 3: Update the Authentication Context (`auth.jsx`)\n\nWe need to modify the authentication context to support the logout functionality.\n\n1. Open `auth.jsx` (inside your `store` folder).\n2. Add the following updates:\n\n```jsx\nimport { createContext, useContext, useState } from \"react\";\n\nexport const AuthContext = createContext();\n\nexport const AuthProvider = ({ children }) =\u003e {\n  const [token, setToken] = useState(localStorage.getItem(\"token\")); // Get token from local storage\n\n  let isLoggedIn = !!token; // Check if the user is logged in\n\n  // Function to store the token\n  const storeTokenInLocalStorage = (serverToken) =\u003e {\n    setToken(serverToken);\n    localStorage.setItem(\"token\", serverToken); // Save token to local storage\n  };\n\n  // Logout function to clear the token\n  const LogoutUser = () =\u003e {\n    setToken(\"\"); // Clear the token in state\n    localStorage.removeItem(\"token\"); // Remove the token from local storage\n  };\n\n  return (\n    \u003cAuthContext.Provider\n      value={{ storeTokenInLocalStorage, LogoutUser, isLoggedIn }}\n    \u003e\n      {children}\n    \u003c/AuthContext.Provider\u003e\n  );\n};\n\n// Custom hook to use the AuthContext\nexport const useAuth = () =\u003e {\n  return useContext(AuthContext);\n};\n```\n\n**What Changed:**\n\n- We added a `LogoutUser` function that clears the token from both state and local storage.\n- `isLoggedIn` now dynamically checks if a token is present.\n\n### Step 4: Update the `Header.jsx` to Show the Logout Button\n\nWe need to make sure the **Logout** link is only shown when the user is logged in.\n\n1. Open `Header.jsx`.\n2. Modify the component like this:\n\n```jsx\nimport { useAuth } from \"../store/auth\"; // Import the AuthContext\n\nconst Header = () =\u003e {\n  const { isLoggedIn } = useAuth(); // Check if the user is logged in\n\n  return (\n    \u003cheader\u003e\n      \u003cnav\u003e\n        \u003cul\u003e\n          {isLoggedIn ? ( // Show Logout link if user is logged in\n            \u003cli\u003e\n              \u003cNavLink\n                to=\"/logout\"\n                className={({ isActive }) =\u003e\n                  `py-2 ${\n                    isActive ? \"text-blue-400\" : \"text-gray-300\"\n                  } hover:text-blue-400`\n                }\n              \u003e\n                Logout\n              \u003c/NavLink\u003e\n            \u003c/li\u003e\n          ) : (\n            \u003c\u003e\n              \u003cli\u003e\n                \u003cNavLink\n                  to=\"/register\"\n                  className={({ isActive }) =\u003e\n                    `py-2 ${\n                      isActive ? \"text-blue-400\" : \"text-gray-300\"\n                    } hover:text-blue-400`\n                  }\n                \u003e\n                  Register\n                \u003c/NavLink\u003e\n              \u003c/li\u003e\n\n              \u003cli\u003e\n                \u003cNavLink\n                  to=\"/login\"\n                  className={({ isActive }) =\u003e\n                    `py-2 ${\n                      isActive ? \"text-blue-400\" : \"text-gray-300\"\n                    } hover:text-blue-400`\n                  }\n                \u003e\n                  Login\n                \u003c/NavLink\u003e\n              \u003c/li\u003e\n            \u003c/\u003e\n          )}\n        \u003c/ul\u003e\n      \u003c/nav\u003e\n    \u003c/header\u003e\n  );\n};\n\nexport default Header;\n```\n\n**Explanation:**\n\n- If the user is logged in (`isLoggedIn` is `true`), show the **Logout** link.\n- If the user is not logged in, show the **Login** and **Register** links.\n\nNow, users can securely log out of your app!\n\n## Day 21 - JWT Token Verification Middleware \u0026 User Data Route\n\nToday, we’ll create a **JWT Token Verification Middleware** to protect routes and allow only authenticated users to access certain endpoints. Additionally, we’ll create a route to get user data from the database based on their JWT token.\n\n### Step 1: Define Routes in `auth-router.js`\n\nFirst, we will add a protected route to fetch user data. This route will use the **JWT Token Verification Middleware** to ensure only logged-in users can access it.\n\n```js\nconst express = require(\"express\");\nconst router = express.Router();\nconst {\n  home,\n  register,\n  login,\n  user,\n} = require(\"../controllers/auth-controller\");\nconst { SignUpSchema, LoginSchema } = require(\"../validators/auth-validator\");\nconst validate = require(\"../middlewares/validate-middleware\");\nconst authMiddleware = require(\"../middlewares/auth-middleware\");\n\nrouter.route(\"/\").get(home);\n\nrouter.route(\"/register\").post(validate(SignUpSchema), register);\n\nrouter.route(\"/login\").post(validate(LoginSchema), login);\n\n// Get User Data Route with authMiddleware protection\nrouter.route(\"/user\").get(authMiddleware, user);\n\nmodule.exports = router;\n```\n\n### Step 2: Create `auth-middleware.js` for JWT Verification\n\nThis middleware checks for the token in the request headers, verifies it using the secret key, and fetches the user data from the database if the token is valid.\n\nIn the `middlewares` folder, create `auth-middleware.js`:\n\n```js\nconst jwt = require(\"jsonwebtoken\");\nconst User = require(\"../models/user-model\");\n\nconst authMiddleware = async (req, res, next) =\u003e {\n  try {\n    const token = req.header(\"Authorization\");\n\n    // Check if token is provided\n    if (!token) {\n      return res\n        .status(401)\n        .json({ message: \"Unauthorized User, Token Not Found\" });\n    }\n\n    // Clean the token by removing 'Bearer'\n    const jwtToken = token.replace(\"Bearer\", \"\").trim();\n\n    // Verify the token\n    const decoded = jwt.verify(jwtToken, process.env.JWT_SECRET);\n\n    // Find the user in the database using the decoded token data\n    const userData = await User.findOne({ email: decoded.email }).select({\n      password: 0,\n    });\n\n    if (!userData) {\n      return res\n        .status(404)\n        .json({ message: `User with email ${decoded.email} not found` });\n    }\n\n    // Attach user data and token to the request object\n    req.user = userData;\n    req.token = jwtToken;\n    req.userID = userData._id;\n\n    // Proceed to the next middleware or controller\n    next();\n  } catch (error) {\n    next({ status: 400, message: error.message });\n  }\n};\n\nmodule.exports = authMiddleware;\n```\n\n### Step 3: Create the User Controller Method\n\nIn `auth-controller.js`, add the controller to handle fetching the user data once they are authenticated.\n\n```js\n// Controller to send user data\nconst user = async (req, res, next) =\u003e {\n  try {\n    const userData = req.user;\n    return res.status(200).json({\n      user: userData,\n      message: \"User data sent successfully\",\n    });\n  } catch (error) {\n    console.error(error);\n    next(error);\n  }\n};\n```\n\n### Step 4: Test the `/user` Route Using Postman\n\n1. **URL**: `http://localhost:3000/api/auth/user`\n2. **Method**: `GET`\n3. **Authorization Header**:\n\n   - Key: `Authorization`\n   - Value: `Bearer \u003cyour_jwt_token\u003e` (replace `\u003cyour_jwt_token\u003e` with the token stored in local storage after login).\n\n   Example:\n\n   ```\n   Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2NmQ0MzRlNzg2NmJjMzExYmVhMjA0MjMiLCJlbWFpbCI6ImFtYW5AZ21haWwuY29tIiwiaXNBZG1pbiI6ZmFsc2UsImlhdCI6MTcyNzYwNTQ3OSwiZXhwIjoxNzI4MjEwMjc5fQ.-CADCRE4t4NGCeRM9KAhOx1orVWweM4jkUUIpUUX084\n   ```\n\n**Screenshot:**\n\n- ![Getting-User-Data](./screenshots/getUserDetails.png)\n\n### Summary\n\n- We created a **JWT Token Verification Middleware** that protects routes by verifying the JWT token sent in the request headers.\n- We added a **user route** to fetch user data from the database only for authenticated users.\n- We tested the route using **Postman** by sending the JWT token in the **Authorization header**.\n\nNow, you have a fully functional protected route for fetching user data! 🎉\n\n## Day 22 - Show User Details in Frontend\n\nToday, we will learn how to **fetch user details** from the backend and display them on the frontend after the user has logged in using a JWT token.\n\n### Step 1: Modify `auth.jsx` to Fetch User Data\n\nIn this step, we’ll add a function in our `auth.jsx` file that fetches user details from the backend using the stored JWT token.\n\n```jsx\nimport { createContext, useContext, useEffect, useState } from \"react\";\n\n// Create the context\nexport const AuthContext = createContext();\n\n// AuthProvider component (Provide the Context value)\nexport const AuthProvider = ({ children }) =\u003e {\n  const [token, setToken] = useState(localStorage.getItem(\"token\"));\n  const [loggedInUser, setLoggedInUser] = useState(\"\"); // Store logged-in user data\n\n  let isLoggedIn = !!token; // Check if the token exists, user is logged in\n\n  const storeTokenInLocalStorage = (serverToken) =\u003e {\n    setToken(serverToken);\n    localStorage.setItem(\"token\", serverToken); // Save token to local storage\n  };\n\n  // Logout function\n  const LogoutUser = () =\u003e {\n    setToken(\"\");\n    return localStorage.removeItem(\"token\");\n  };\n\n  // Get User Data from the backend\n  const getUserData = async () =\u003e {\n    try {\n      const backendURL = import.meta.env.VITE_BACKEND_URL; // Backend URL from environment\n      const url = `${backendURL}/api/auth/user`; // API endpoint for user data\n\n      const response = await fetch(url, {\n        method: \"GET\",\n        headers: {\n          Authorization: `Bearer ${token}`, // Send token with the request\n        },\n      });\n\n      if (response.ok) {\n        const data = await response.json(); // Get user data from the response\n        setLoggedInUser(data); // Set user data in state\n      } else {\n        console.log(\"Failed to Fetch Data\");\n      }\n    } catch (error) {\n      console.log(error);\n    }\n  };\n\n  // Fetch user data once the component is mounted\n  useEffect(() =\u003e {\n    getUserData();\n  }, []);\n\n  return (\n    \u003cAuthContext.Provider\n      value={{ storeTokenInLocalStorage, LogoutUser, isLoggedIn, loggedInUser }}\n    \u003e\n      {children}\n    \u003c/AuthContext.Provider\u003e\n  );\n};\n\n// Custom hook to use the Auth Context\nexport const useAuth = () =\u003e {\n  return useContext(AuthContext);\n};\n```\n\n### Step 2: Display User Data in the Frontend\n\nNow that the user data is fetched and stored in `loggedInUser`, you can display it anywhere in your app, such as in the **Header** component or a **Profile** page.\n\nHere’s how you can access the user details in the `Header.jsx`:\n\n```jsx\nimport { useAuth } from \"../store/auth\"; // Import the useAuth hook\n\nconst Header = () =\u003e {\n  const { loggedInUser } = useAuth(); // Get the user data from the Auth Context\n\n  return (\n    \u003cheader\u003e\n      {loggedInUser?.user?.username \u0026\u0026 (\n        \u003cp\u003eWelcome, {loggedInUser.user.username}!\u003c/p\u003e // Display the username\n      )}\n    \u003c/header\u003e\n  );\n};\n\nexport default Header;\n```\n\n### Step 3: Testing the Feature\n\n1. **Login**: First, log in as a user to get a valid JWT token stored in the browser's local storage.\n2. **Verify Token**: The `getUserData` function will automatically use this token to fetch the user's data from the backend.\n3. **View Data**: You should now see the logged-in user’s **username** (or any other data) displayed in the component where you accessed `loggedInUser`.\n\n### Summary\n\n- We updated the `auth.jsx` file to include a function for fetching **user details** from the backend using the JWT token stored in local storage.\n- We used the `useAuth` hook to access the **user data** and display it in the frontend, such as in the `Header` or other components.\n- The user’s details will now be shown after a successful login.\n\nNow, you can easily display user information anywhere in your app after they have logged in! 🎉\n\n## Day 23 - Handling Login \u0026 Registration Form Validation with React Toastify\n\nToday, we'll integrating **React Toastify** to display success and error messages in our Login and Registration forms.\n\n\n### Step 1: Install React Toastify\n\nIn your frontend project folder, install `react-toastify`:\n\n```bash\nnpm i react-toastify\n```\n\n---\n\n### Step 2: Configure Toastify in `main.jsx`\n\nImport `ToastContainer` and its CSS to make Toastify available across the app. Add `\u003cToastContainer /\u003e` to the top-level component structure in `main.jsx`.\n\n**Example changes in `main.jsx`:**\n\n```jsx\nimport 'react-toastify/dist/ReactToastify.css';\nimport { ToastContainer } from 'react-toastify';\n\n// Wrap App with ToastContainer and AuthProvider\ncreateRoot(document.getElementById(\"root\")).render(\n  \u003cAuthProvider\u003e\n    \u003cToastContainer /\u003e {/* This enables toast notifications */}\n    \u003cStrictMode\u003e\n      \u003cRouterProvider router={router} /\u003e\n    \u003c/StrictMode\u003e\n  \u003c/AuthProvider\u003e\n);\n```\n\n---\n\n### Step 3: Add Toastify Notifications in Login Component\n\nIn the `Login.jsx` component, import and use Toastify to display feedback messages.\n\n**Example steps in `Login.jsx`:**\n\n1. **Import Toastify**: Import `toast` from `react-toastify`.\n2. **Handle Success and Error**: Inside `handleSubmit`, call `toast.success()` or `toast.error()` based on the response.\n\n```jsx\nimport { toast } from \"react-toastify\";\n\n// Handle form submission\nconst handleSubmit = async (e) =\u003e {\n  e.preventDefault();\n  try {\n    const response = await fetch(`${BACKEND_URL}/api/auth/login`, { /* config */ });\n    const data = await response.json();\n\n    if (response.ok) {\n      storeTokenInLocalStorage(data.token); // Save token\n      toast.success(\"Login successful\");     // Success message\n      navigate(\"/\");\n    } else {\n      toast.error(data.message[0]?.message || \"Login failed\"); // Error message\n    }\n  } catch (error) {\n    toast.error(\"An error occurred. Please try again.\");       // Error message\n  }\n};\n```\n\n---\n\n### Summary\n\n- **Install React Toastify** to enable toast notifications.\n- **Configure Toastify in `main.jsx`** by adding `\u003cToastContainer /\u003e` to the root component.\n- **Add Toast Messages** in `Login` and `Register` components to improve user feedback on form submission.\n\nBy following these steps, you enhance the user experience by providing immediate feedback on login and registration actions. 🎉\n\n\n# Day 24 - Admin Panel Setup \u0026 Retrieving User Data\n\nToday, we'll set up an admin endpoint in the backend to fetch all registered user data, excluding passwords. This will be useful for viewing user data in an admin panel.\n\n---\n\n### Step 1: Create Admin Router\n\nIn the `backend/router` folder, create a new file named **`admin-router.js`** to define the routes for the admin functionality.\n\n**admin-router.js:**\n```js\nconst express = require('express');\nconst getAllUsers = require('../controllers/admin-controller'); \nconst router = express.Router();\n\n// Route to get all registered users\nrouter.route('/users').get(getAllUsers);\n\nmodule.exports = router;\n```\n\n---\n\n### Step 2: Create Admin Controller\n\nIn the `backend/controllers` folder, create a new file named **`admin-controller.js`**. Here, we'll define a function to fetch all users, excluding sensitive information such as passwords.\n\n**admin-controller.js:**\n```js\nconst User = require('../models/user-model');\n\n// Fetch all registered users without passwords\nconst getAllUsers = async (req, res, next) =\u003e { \n    try {\n        const users = await User.find({}, { password: 0 });  // Exclude passwords\n        if(!users) {\n            return res.status(404).json({ message: 'No users found' });\n        }\n        res.status(200).json(users);\n    } catch (error) {\n        next(error); \n    }\n};\n\nmodule.exports = getAllUsers;\n```\n\n---\n\n### Step 3: Update the Main Backend File\n\nIn **`index.js`**, import the new admin route and use it to enable the `/api/admin/users` endpoint.\n\n**index.js:**\n```js\nconst adminRoute = require('./router/admin-router');\n\n// Admin route for accessing registered users\napp.use('/api/admin', adminRoute);\n```\n\n---\n\n### Step 4: Test with Postman\n\n1. Open Postman and send a **GET** request to `http://localhost:3000/api/admin/users`.\n2. You should see a response with a list of registered users, excluding passwords.\n- ![Users Data in Postman](./screenshots/admin_get_user.png)\n\n---\n\n### Summary\n\n- **Created a new admin route** to manage user data retrieval.\n- **Configured the controller** to fetch user data, excluding passwords.\n- **Integrated the route** into the main app file and tested the endpoint using Postman.\n\nThis setup will make it easy to expand our admin functionality for managing users. 🎉\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famankumarsinhagithub%2Fmern","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Famankumarsinhagithub%2Fmern","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Famankumarsinhagithub%2Fmern/lists"}