
MERN Stack projects with source code: Full Stack Gadgets Store App | React JS, MongoDB, Express, Node JS
MERN Stack projects with source code: This Full Stack Gadgets Store React Application is a feature-rich platform designed to provide a seamless shopping experience. The project demonstrates an optimized architecture with reusable React components, efficient state management using the Context API, and interactive user functionalities. It incorporates React Hook Form for collecting and storing data in a remote MongoDB database, along with Custom Hooks for fetching data from the database.
The backend is built using Node.js, the Express web framework, and MongoDB, with Mongoose for object modeling. It utilizes a remote MongoDB database for storing products and orders, complete with robust CRUD operations. Key backend features include setting up MongoDB models, handling database connection logic, creating controllers, defining API routes to interact with the controllers, and connecting the backend to the frontend for seamless integration. Below are the main components and features of the application:
Front-End Core Components & Functionalities
Home Page Component
Displays products from the Best Sellers and New Arrivals categories, dynamically fetched from a remote MongoDB database using a custom React hook.
Allows users to add available products to their shopping cart with a notification message.
Prevents users from adding out-of-stock items to the cart.
Provides links to a detailed Product Page for individual product views, utilizing the ObjectId from the MongoDB database collection.
Product Page Component
Displays detailed information about a product using its ObjectId retrieved from the MongoDB database collection.
Shows an "Out of Stock" message and disables the "Add to Cart" button for unavailable items.
Includes options to:
Add to Cart for available items.
Increase product quantity via a "+" button.
Decrease product quantity via a "-" button, automatically removing the product when the quantity reaches zero.
Collection Page Component
Fetches products from a remote MongoDB database using a custom React hook and includes a catalog with advanced filtering and sorting options.:
Main Categories: New Arrivals, Best Sellers, On Sale.
Subcategories: Wrist Watches, Headphones, Smart Watches, Bluetooth Speakers.
Sorting options: Price Low to High, Price High to Low.
Search functionality for product names.
Allows users to add products to their cart and view detailed product pages using its ObjectId retrieved from the MongoDB database collection.
Cart Page Component
Displays detailed cart information, including:
Product name, price, quantity, total cost per item, and overall total (including tax and delivery fees).
Features cart management options:
Increment/decrement quantity using "+" and "-" buttons.
Remove items from the cart if quantity reaches zero.
Delete entire items from the cart.
Links back to the Product Page using its ObjectId retrieved from the MongoDB database collection, where quantities of each product are dynamically updated based on user interactions (e.g., adding/removing products, changing quantities).
Enables users to proceed to the Checkout Page.
Checkout Page Component
Displays a detailed order summary.
Collects user information using React Hook Form.
On order submission:
Saves 'order details' to the global state and stores them in the remote MongoDB database collection named "orders".
Redirects users to a Thank You page confirming their purchase, displaying the order ID retrieved from the MongoDB database collection "orders".
ProductForm Page Component The ProductForm React component utilizes the ProductFormFields component, which employs React Hook Form to collect product data and store it in the remote MongoDB database collection "products" and the ProductListing component fetches and displays all products from the "products" collection, allowing the product admin to delete or edit products.
Global State Management with React Context API
The application leverages React Context API for efficient state management across components:
Manages global states for:
Order Details
Cart Information
Delivery Fee & Tax Rate
Product Search and Search Bar Functionality
Persisting user and cart information in the global state across browser refreshes using localStorage.
Handles key functionalities:
Adding/removing products from the cart.
Incrementing/decrementing product quantities.
Calculating product totals, cart total, and cart item count (displayed on the NavBar).
Technical Highlights
Responsive Design: Fully adaptable for various devices.
Interactive UI: Smooth user interactions with real-time updates in cart and product quantities.
Ensuring a consistent font and color theme across all pages for a cohesive user experience.
Form Handling: Simplified and validated user input collection with React Hook Form.
This project demonstrates the power of reusable components, effective global state management, and user-centric design, making it an excellent foundation for building a robust e-commerce platform.
Live Application Resources:
Install Plugins: Tailwind CSS IntelliSense, es7+ (ES7+ React/Redux/React-Native snippets), Thunder Client
Version Control: GitHub
https://color.adobe.com/explore Vercel: Build and deploy the best web experiences with the Frontend Cloud
Creating Front End React App
Open the folder "mern-gadgets-store" in VS Code
Creating a Vite Project Using React
www.tailwindcss.com -> Framework Guides -> Vite -> Using React -> Run the commands
> npm create vite@latest
> Projectname: frontend
> Select a framework: React
> Select a variant: JavaScript
> cd frontend
> npm install
> Run your build process with "npm run dev" -> http://localhost:5173/
Delete "App.CSS" & Remove everything from index.css files and add your custom style..
Installing Tailwindcss:
www.tailwindcss.com -> Framework Guides -> Vite -> Using React -> Run the commands
> npm install -D tailwindcss postcss autoprefixer
> npx tailwindcss init -p
Configure your template paths:
Add the paths to all of your template files in your tailwind.config.js file.
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {},
},
plugins: [],
}
Add the Tailwind directives to your CSS:
Add the @tailwind directives for each of Tailwind’s layers to your ./src/index.css file.
@tailwind base;
@tailwind components;
@tailwind utilities;
Installing Libraries:
>npm install react-icons react-router-dom react-hook-form NOTE: Encapsulate the 'App' component with 'BrowserRouter' & 'StoreContextProvider' in the 'main.jsx'
<StoreContextProvider>
<BrowserRouter>
<App />
</BrowserRouter>
</StoreContextProvider>
Add Global styles in "index,css" file
Creating your own components... Configure Google Fonts and select the color palate.
Step1: Set Up the Backend (Express, MongoDB, Node.js)
1. Create a New Directory for Your Backend: Start by creating a separate folder for your backend inside your project directory:
>mkdir backend
>cd backend
2. Initialize a New Node.js Project: Initialize the Node.js app with the following command:
>npm init -y
This creates a package.json file.
3. Install Required Dependencies: Install the following packages for setting up the backend:
>npm install express mongoose cors dotenv
express: Web framework for Node.js.
mongoose: MongoDB object modeling tool.
cors: Middleware to handle Cross-Origin Resource Sharing (needed for React frontend to communicate with your backend).
dotenv: To handle environment variables.
4.Using MongoDB Atlas for Cloud Storage https://www.mongodb.com/atlas
To get started, create an Organization by selecting 'MongoDB Atlas' as cloud service, within an Organization you can create project.
For a project, create a database instance, cluster( overall "container" for your databases) by choosing your cloud provider, region, and specs.(Free Tier)
Add New Database User: Create a database user to grant an application or user access to databases and collections in your clusters in this Atlas project.
Go to "Database Access" then create username, auto generated password, and copy it, and also select one built-in role for this user.
Go to "Network Access" then Edit IP address as 0.0.0.0/0
Click on your project name, you will your project's cluster, then choose "connect" -> "Drivers" -> choose "Node.js" option as driver, copy the MongoDB URI, then add it in the .env file.
The URI you get from MongoDB Atlas typically looks like this:
mongodb+srv://<username>:<password>@clustername.mongodb.net/<databasename>?retryWrites=true&w=majority
Replace <db_password> with the password for the user-name database user.
NOTE: You can access database collections here, Project -> Under Cluster -> Browse Collections.
Create a Database: Click project name -> clusters -> Browse Collections -> Create Database
After creating the cluster, you need to create a database inside it.
Create Collections:
Inside the database, you create collections to store related data.
How the MongoDB URI Connects to a Database
MongoDB URI Format: The URI you get from MongoDB Atlas typically looks like this:
mongodb+srv://<username>:<password>@clustername.mongodb.net/<databasename>?retryWrites=true&w=majority
<username> and <password>: The credentials for accessing the database.
@clustername.mongodb.net: The host where your cluster is running.
<databasename>: The name of the database you want to connect to.
Additional parameters (?retryWrites=true&w=majority): Options for connection behavior.
Database Name in the URI:
The <databasename> part of the URI specifies which database you are connecting to.
Example: If your URI is
mongodb+srv://user:password@clustername.mongodb.net/TaskManagerDB
5. Create .env File: In the root of your backend folder, create a .env file to store sensitive information like the MongoDB URI:
MONGO_URI=mongodb+srv://<username>:<password>@clustername.mongodb.net/<databasename>?retryWrites=true&w=majority
6. Steps to Create a .gitignore File for the Backend
Create the .gitignore File: At the root of your backend project directory (the same level as package.json), create a file named .gitignore.
Add Entries to the .gitignore File: Add the following entries to ignore sensitive files and folders:
# Environment variables
.env
# Node modules
node_modules/
# Logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# OS-specific files
.DS_Store
Thumbs.db
# Build files
dist/
Step 2: Set Up MongoDB Models
1.Create Models for Your Data: Let’s create models such as Product, . Create a 'models' folder and a file 'Product.js' inside it: Then, define the schema for the Product model:
2.Handle MongoDB connection logic: create a file db.js inside the folder 'config', encapsulating the logic (database connection) can be reused or modified independently.
const mongoose = require('mongoose');
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
console.log("Connected to MongoDB");
} catch (err) {
console.error("Failed to connect to MongoDB", err);
process.exit(1); // Exit the process with failure
}
};
module.exports = connectDB;
Crate DB Connectivity Testing File: Create file named "testDbConnection.js" to test teh MongoDB database connection.
require('dotenv').config(); // Load environment variables
const connectDB = require('./config/db'); // Import your db.js
const testConnection = async () => {
await connectDB(); // Attempt to connect to MongoDB
};
testConnection();
Run the command, form the "backend" folder of your app and test MongoDB connection. >node testDbConnection.js
3. Create the Controller: In this case, we’ll create a productController.js inside 'controllers' folder that handles the business logic for product-related(users API) actions (e.g., registering a product, getting products from the database). Create controller functions that handle the logic for each route in the users API:
4. Create API Routes to use the Controller: Create a 'routes' folder and a file for the product routes, products.js:
Create routers for the products API that handles requests for the products API:
5. Create the Server (Express Setup): In the backend folder, create a new file server.js and add the following code to set up your Express server:
NOTE: Link Routes to Express: Import the routes and link them to your Express app:
const productRoutes = require('./routes/products');
app.use('/api/products', productRoutes); // Prefix all routes with /api/products
Step 3: Test the Backend
1. Start the Backend Server: Run the server.js from the "backend" folder, to ensure everything is set up correctly:
>node server.js
2. Test the Endpoints: Use "Thunder Client" or Postman to test your API endpoints:
POST localhost:3001/api/products Test creating a new product, send a JSON body like
{
"name": "Classic Wrist Watch",
"description": "Timeless elegance meets modern precision. Crafted for those who value sophistication and reliability. Perfect for any occasion, from formal to casual.",
"price": 120.99,
"image": ["https://images.pexels.com/photos/13590094/pexels-photo-13590094.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"https://images.pexels.com/photos/280324/pexels-photo-280324.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"https://images.pexels.com/photos/14377200/pexels-photo-14377200.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1"
],
"category": "Best Sellers",
"subCategory": "Wrist Watch",
"color": "Black",
"date": "2024-10-01",
"inStock": false,
"rating":5,
"offer": "Buy 1, get 20% off on the second wristwatch",
"discount": 20.00
}
GET localhost:3001/api/products Test fetching all users.
Step 4: Connect Backend with Frontend (React)
On the React side, you will continue to make API calls using Axios (as shown in the earlier steps). Here's an example of how you can connect to the backend:
1. Create a Component to Register Products
import React from 'react';
import { useForm } from 'react-hook-form';
const ProductForm = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
const onSubmit = async (data) => {
try {
const response = await fetch('http://localhost:3001/api/products/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
if (!response.ok) {
throw new Error('Failed to create product');
}
const result = await response.json();
alert('Product created successfully!');
console.log(result);
} catch (error) {
console.error(error.message);
alert('Error creating product');
}
};
return (
<div className="max-w-xl mx-auto p-4">
<h2 className="text-2xl font-bold mb-4">Create Product</h2>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<div>
<label className="block font-medium">Name</label>
<input
type="text"
{...register('name', { required: 'Name is required' })}
className="w-full border px-3 py-2 rounded"
/>
{errors.name && <p className="text-red-500">{errors.name.message}</p>}
</div>
<div>
<label className="block font-medium">Description</label>
<textarea
{...register('description', { required: 'Description is required' })}
className="w-full border px-3 py-2 rounded"
></textarea>
{errors.description && (
<p className="text-red-500">{errors.description.message}</p>
)}
</div>
<div>
<label className="block font-medium">Price</label>
<input
type="number"
step="0.01"
{...register('price', {
required: 'Price is required',
valueAsNumber: true,
})}
className="w-full border px-3 py-2 rounded"
/>
{errors.price && <p className="text-red-500">{errors.price.message}</p>}
</div>
<div>
<label className="block font-medium">Image URLs (comma-separated)</label>
<input
type="text"
{...register('image', {
required: 'At least one image URL is required',
})}
className="w-full border px-3 py-2 rounded"
/>
{errors.image && <p className="text-red-500">{errors.image.message}</p>}
</div>
<div>
<label className="block font-medium">Category</label>
<input
type="text"
{...register('category', { required: 'Category is required' })}
className="w-full border px-3 py-2 rounded"
/>
{errors.category && (
<p className="text-red-500">{errors.category.message}</p>
)}
</div>
<div>
<label className="block font-medium">Sub Category</label>
<input
type="text"
{...register('subCategory')}
className="w-full border px-3 py-2 rounded"
/>
</div>
<div>
<label className="block font-medium">Color</label>
<input
type="text"
{...register('color')}
className="w-full border px-3 py-2 rounded"
/>
</div>
<div>
<label className="block font-medium">Date</label>
<input
type="date"
{...register('date')}
className="w-full border px-3 py-2 rounded"
/>
</div>
<div>
<label className="block font-medium">In Stock</label>
<input
type="checkbox"
{...register('inStock')}
className="mr-2"
/>
<span>Available</span>
</div>
<div>
<label className="block font-medium">Rating</label>
<input
type="number"
step="1"
{...register('rating', { min: 0, max: 5 })}
className="w-full border px-3 py-2 rounded"
/>
</div>
<div>
<label className="block font-medium">Offer</label>
<input
type="text"
{...register('offer')}
className="w-full border px-3 py-2 rounded"
/>
</div>
<div>
<label className="block font-medium">Discount</label>
<input
type="number"
step="0.01"
{...register('discount', { min: 0, max: 100 })}
className="w-full border px-3 py-2 rounded"
/>
</div>
<button
type="submit"
className="w-full bg-blue-500 text-white py-2 rounded hover:bg-blue-600"
>
Submit
</button>
</form>
</div>
);
};
export default ProductForm;
Steps to Run the Backend:
Start Your Backend Server:
Navigate to your backend project directory in the terminal.
Run the following command to start the server
node server.js
Check the Backend:
Verify that the backend is running by checking the console output for a message like Server running on port 3001.
Use tools like Thunder Client or Postman to test the API endpoints (e.g., http://localhost:3001/api/products/) with a sample POST request.
Steps to Run the Frontend:
Start Your React Frontend:
Navigate to your React project directory in a separate terminal.
Start the development server
npm run dev
This will usually run the React app on http://localhost:5173
Check the Frontend:
Open your browser and visit http://localhost:5173.
Navigate to the component where the form is rendered and test submitting the form.
GitHub Commands:
git init
git add .
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/codingZ2M/dummy.git
git push -u origin main
Comments