This project aims to create an interactive and user-friendly e-commerce platform where users can browse products, place orders, and make secure payments. The platform is designed to provide a seamless shopping experience while ensuring secure transactions and personalized user interactions.
- Implementation of secure login, logout, and signup functionalities.
- Ensures user data protection and session management for a seamless experience.
- Explores how authentication enhances both security and usability of the platform.
- Development of a dedicated Product Page to display all available products.
- Integration of APIs to fetch and dynamically manage product data.
- A personalized Orders Page where users can:
- Upon selecting a product, users are redirected to this page to review and place an order for the selected items.
- View their order history.
- Access order-specific details dynamically.
- Leverage APIs to fetch user-specific order data securely.
- Simulation of a Payment Gateway to handle user purchases.
- User-friendly interface to review purchase details and finalize the transaction
- created a folder in code editor using the command "npm create vite@ latest frontend"(React)
- create node modules package using the command "npm install"
- Install the required packages from tailwind.css using the following commands "npm install -D tailwindcss postcss autoprefixer.
- Initialize using "npx tailwindcss init -p".
- After initializing we get the tailwind.config.js file
- Config helps apply style to the entire frontend project
- Edited the content part of tailwind.config.js file.
- Added tailwind directories to css (index.css and App.css)
- Express helps us write the APIs for the app
- Mongoose configures the database with the backend
- cors allows a web application running at one origin to request resources from a different origin.
- nodemon is a utility that automatically restarts your Node.js application when it detects file changes in the directory where the application is running.
- create a folder using the command "mkdir backend"
- Initialize backend environment "npm init -y" edit the package name, give a description.
- After doing this we can see package.json file
- Install packages "express,nodemon,cors"
- create src folder , inside src folder create the following folders and files named middleware, config(connect backend to teh database), routes, controllers and index.js file
- create a components folder under src , under components folder create authorization and Navbar folder
- Inside Authorization folder create Login.jsx and Signup.jsx files
- Edit App.jsx file
- Edit Login.jsx file
- In Login.jsx file, added 2 input fields with placeholders for entering email address and password respectively . Also added a button to Login after entering the details.
- Added styling using taildwind css.
- The server is configured using the Express.js framework in the app.js file.
- The dotenv package is used to load variables from the .env file for secure configuration.
- A basic route is implemented to validate that the server is running.
- The server listens on the port specified in the .env file.
- MongoDB is integrated using the Mongoose library. The database.js file contains the logic for connecting to the MongoDB database.
- The connectDatabase function uses mongoose.connect() to establish a connection to MongoDB.
- Logs descriptive error messages in case the connection fails.
- Using dotenv ensures credentials are not hardcoded.
- Displays a success message with the database host upon connection.
- The index.js file integrates the server and database connection, ensuring the database is connected whenever the server starts.
- The Express server is started and listens on the specified port.
- The connectDatabase function is invoked during the server startup process.
- Logs messages for both successful server startup and database connection.
- The ErrorHandler.js file defines a custom error handler class to streamline error management.
- Error Class: Extends the native JavaScript Error class to add a status code.
- Stack Trace: Captures the error stack for debugging purposes.
- The User Model defines the schema for storing user data in MongoDB.
- Name, Email, and Password: Required fields for every user.
- Address: A nested structure that supports fields like city, country, and zip code.
- Avatar: Stores user-uploaded file information (URL and public ID).
- Role: Identifies the type of user (default: "user").
- Reset Password Token: Used for password recovery processes.
- Controllers contain the logic for handling user data. They act as the intermediaries between the database and the routes.
- A controller manages the interaction between routes and models.
- Check if the user exists in the database using findOne
- If not, create a new user document using the save() method.
- Error Handling: Centralize error handling for better debugging.
- Multer is middleware that handles requests, primarily used for file uploads.
- Custom Storage: Allows defining a storage destination and filename format.
- Ease of Use: Simplifies handling file uploads in Express.js applications.
In this milestone, the focus was on creating the frontend for the sign-up page, implementing form validation using RegEx, and setting up routing using React Router. This work ensures that users can seamlessly register on the platform while providing accurate and valid information.
Designed a clean and user-friendly signup page using HTML and Taliwind CSS.
- Name: For users to provide their full name.
- Email: To capture the user's email address.
- Password: To allow users to set up a secure password.
- File Upload: Allows users to upload a file in .jpg, .jpeg, or .png format.
- Built a validation object using JavaScript Regular Expressions (RegEx) to ensure data accuracy.
- Name: Checks that the name is not empty and only contains valid characters.
- Email: Validates that the email follows the standard email format (e.g., [email protected])
- Password: Ensures the password meets security criteria, including:
- Minimum length of 8 characters, Contains at least one uppercase letter, one lowercase letter and one special character.
- Added error messages for invalid inputs to guide users in correcting their data.
- Added file upload handling to accept images in the specified formats.
- Displayed error messages dynamically for invalid inputs, providing clear feedback to users for corrections.
-
Integrated React Router to enable seamless navigation between pages.
-
Configured routes for the application, including:
- Signup Page: /Signup
- Login Page: /Login
- Home Page: /
-
Implemented navigation components to allow users to switch between pages effortlessly.
-
Updated the App component to include the necessary routes using and from React Router.
This milestone focuses on implementing email verification for user signup using JWT (JSON Web Tokens) and Nodemailer. By the end of this milestone, the application will:
- Generate a JWT token during user signup.
- Send a verification email with a link containing the token.
- Verify the token to activate the user account.
-
Check User Existence: Ensure the email provided by the user is not already in the database. If the user exists, return an error.
-
Create a New User: Save the user's details (such as name, email, and password) in the database.
-
Generate JWT Token: Create a JWT token that encodes essential user information (e.g., name and email) and sign it with a secret key (SECRET_KEY) defined in your .env file. Set an appropriate expiration time for the token.
-
Construct the Link: After generating the token, create a verification link by appending the token as a query parameter. The link should point to the verification endpoint of your application, e.g., http://localhost:8080/user/activation/:token.
-
Store Token in Email: Ensure the generated link is included in the email body, providing users with clear instructions to verify their account.
-
Set Up Nodemailer: Use Nodemailer to configure an email transporter. Define SMTP settings, such as the service (e.g., Gmail) and authentication credentials.
-
Compose Email: Craft an email containing the verification link.
-
Send the Email: Trigger the email-sending function after successfully creating a user and generating the verification token.
-
Token Verification Logic: In the verification endpoint, decode the JWT token using the secret key. Validate that the token has not expired and that its data matches the expected format.
-
Activate User: If the token is valid, locate the user in the database using the decoded information (e.g., email). Update their activation status to indicate their account is verified.
-
Handle Errors: Return appropriate responses for invalid or expired tokens, and ensure robust error handling to prevent unauthorized access.
In this milestone, we implemented two essential routes: signup and login to handle user authentication. These routes ensure that user credentials are securely stored and validated.
-
Extract User Data:
- Receive user input sent via the request body: name, email, and password.
-
Check if the User Already Exists:
- Query the database to see if an entry with the provided email already exists.
- If Yes, return a response saying: "User already present, please login directly."
-
Hash the Password:
- If the user is not already registered, hash the password to ensure it is securely stored.
- Use hashing libraries like Bcrypt.js for encryption.
- The original plain-text password is never stored in the database.
-
Save the User Data to the Database:
- Create a new user entry with the following fields:
- name
- hashed password
- Create a new user entry with the following fields:
-
Send a Success Response:
- Return a response confirming that the user has been successfully registered.
The login route authenticates existing users.
-
Extract User Data:
- Receive user credentials sent via the request body: email and password.
-
Check if the User Exists in the Database:
- Query the database to find a user with the provided email.
- If No User Found → Return a response saying: "User not found, please signup first."
-
Validate the Password:
- Compare the provided plain-text password with the hashed password stored in the database.
- Use a hashing library (e.g., Bcrypt) to handle the comparison securely.
-
Generate an Authentication Token:
- If the password matches, generate a secure token (e.g., JWT) to manage user sessions.
- Send the token as a cookie for client-side storage.
-
Send a Success Response:
- Return a response confirming that the user has successfully logged in.
-
Reusable Design: A Card Component was created to display the key details of each product. This component is flexible, meaning it can be reused for any product with different details. The card displays:
- Product name (
title) - Product image (
image) - Product price (
price) - Product description (
description)
This ensures that the component is dynamic, allowing it to be used for various products without hardcoding values into the component.
- Product name (
-
Dynamic Content:
- To make the card component truly dynamic, it receives props from its parent component.
- These props include the product details like name, image URL, price, and description.
- This design allows the component to render different products by simply passing in new data.
- The
Cardcomponent does not need to be modified for each new product; the data just needs to be passed correctly when rendering it.
- Grid Layout:
- To ensure a visually organized and responsive display of product cards, a grid layout was implemented using Tailwind CSS.
- This grid layout arranges the cards in rows and columns. Each card is placed in a flexible container, which adapts to the size of the screen.
In this milestone our goal was to create a product entry page for an e-commerce platform. The product entry form allows users to submit information about a product, including title, description, discounted and original prices, stock quantity, category, rating, and product images. Upon form submission, the product details are sent to a server using an HTTP POST request for further processing.
- I used React, a popular JavaScript library for building user interfaces.
- Axios, a promise-based HTTP client, was used to handle API requests for submitting the form data.
- The form captures multiple product details through various form fields, including:
- Title
- Description
- Discounted price
- Original price
- Stock quantity
- Category
- Rating
- Product images
- For each input, event handlers were created to update the form state whenever the user interacts with the fields.
- React's useState hook was used to store and manage the form data as the user types in the fields.
- This state includes the product title, description, rating, price details, quantity, category, and uploaded images.
- A separate state variable tracks any input errors, which are displayed to the user if they fail to enter necessary details or if the values don't meet the validation requirements.
- An input element with the type="file" attribute was used to allow users to upload product images.
- A change event handler captures the selected files, converting them into an array and storing them in the state.
- Before submitting the form, basic validation checks were implemented to ensure that all required fields are filled in and contain valid data.
- If any of the conditions were not met, an error message is displayed to inform the user.
- Upon successful form validation, a FormData object was created to append the input data, including both text-based information (such as title and price) and the images (file paths).
- This data is then sent to the server using Axios via an HTTP POST request. The server is assumed to handle the product data on the backend.
- The application used React Router to manage navigation between different pages. The user can navigate between the homepage, login, signup, and the product entry page.
- Each route is linked to a specific component, with the ProductEntryPage being one of the primary components for submitting product details.
- Tailwind CSS was used for styling the form and ensuring a responsive and user-friendly interface.
- The form was designed with appropriate labels, input fields, and buttons to ensure a clean, accessible layout for users to easily submit product information.
- The form includes error handling that checks whether the input fields contain valid data and alerts the user if there are any missing or invalid inputs.
- This includes checking if fields like price and quantity contain positive values and ensuring text fields are not left empty.
- In the App.jsx file, React Router was used to set up the navigation, this route is associated with the ProductEntryPage component. Users can navigate to this page to enter product details, including images, prices, and other attributes.
This part of the project is designed to handle product uploads in an e-commerce platform, where products are accompanied by images that are uploaded to a cloud storage service (Cloudinary) and stored in a database
- Cloudinary Configuration (cloudinary.js)
- Setup Cloudinary
- Initially, we integrated Cloudinary, a cloud-based image and video management service, to handle image uploads. We used the cloudinary package to communicate with Cloudinary’s API.
- The configuration is done using credentials, including cloud_name, api_key, and api_secret. These values are stored in environment variables for security and flexibility, and are loaded through the dotenv package.
- Environment-Based Configuration
- We conditionally loaded the environment variables only if the application is not in production. This ensures that the sensitive API keys are not exposed in the production environment.
- Setup Cloudinary
- Product Routes (product.route.js)
- Define the Route
- A route for creating products (/create-product) was set up using Express.js. This route handles POST requests to add a new product to the platform.
- Image Upload with Multer
- We used the multer middleware to handle file uploads. It temporarily stores files in a folder (temp-uploads) before they are uploaded to Cloudinary. The upload.array('files', 5) specifies that a maximum of 5 files can be uploaded in a single request.
- Route Handler Integration
- The route handler for creating the product is linked to a controller function (createProductController), where the actual business logic for product creation happens.
- Define the Route
- Product Model (Product.model.js)
- Define the Schema
- We created a Mongoose schema to define the structure of the product data in the database. Fields like title, description, rating, discountedPrice, originalPrice, quantity, and category were added as required fields, with validation in place for certain types (e.g., number or string).
- Default Image and Enum Validation
- A default image URL was provided in the schema in case no images are uploaded. The category field was set up as an enum to ensure it can only take one of three values: male, female, or kids.
- Model Creation
- Using the schema, we created a ProductModel using Mongoose’s model method. This model is used to interact with the MongoDB database to store product data.
- Define the Schema
- Product Controller (Product.controller.js)
- Handle Product Creation
- The createProductController is the core logic for handling product creation. It receives product data (e.g., title, description, price, etc.) and image files from the request body.
- Handle Image Uploads
- For each uploaded image, we used the Cloudinary uploader.upload method to upload the file to Cloudinary’s cloud storage. Each file is uploaded individually, and once uploaded, we remove the local temporary file using fs.unlinkSync.
- Save Product Data
- After the images are uploaded and URLs are retrieved from Cloudinary, we save the product details to the database. The images are stored as an array of URLs in the product document.
- Error Handling
- Errors during the process, such as file upload issues (handled by multer) or server errors, are caught and responded to with appropriate error messages and status codes.
- Handle Product Creation
- Temporary Uploads Folder (temp-uploads)
- Storage for Uploaded Files
- The temp-uploads folder is used to temporarily store files before they are processed and uploaded to Cloudinary. This folder is managed by the multer middleware to handle file storage.
- Storage for Uploaded Files
This milestone focuses on creating an endpoint to fetch all product data from a MongoDB database and send it to the client.
- Write a GET endpoint to fetch product data from the database.
- Test the endpoint to ensure it retrieves the required data correctly.
-
Controller Implementation:
- Create a function in the controller to query the database for all product data using the product model.
- Return the fetched data along with a success message.
- Handle errors by sending an appropriate error message and status code.
-
Route Definition:
- Define a GET route in the routes file.
- Link the route to the controller function responsible for fetching product data.
- Ensure proper response structure with HTTP status codes for both success and failure scenarios.
- Ensure MongoDB is properly connected to the application.
- Populate the database with sample product data for testing.
- Validate that the product schema aligns with the data structure being fetched by the endpoint.
-
Start the backend server: Ensure the server is running and the endpoint is active.
-
Verify the functionality: Use tools like Postman to make GET requests to the
/get-productsendpoint.- Check if the response contains the product data.
- Confirm that the success message is returned.
- Test error handling by introducing potential failure scenarios (e.g., database connection issues).
-
Database Validation: Verify that the data returned by the endpoint matches the data stored in the MongoDB collection.
- This milestone focuses on building an endpoint to send all product data to the frontend.
- The data will be fetched from a MongoDB database and displayed dynamically on the frontend using a product card component.
- Create an endpoint
/product/get-productsto send all product data to the frontend. - The endpoint will send the product data in a response format, including fields like title, image, description, price, and ratings.
- MongoDB is used to store product data.
- The backend will query MongoDB and retrieve all products and sending all available product data to the frontend.
- Cross-Origin Resource Sharing (CORS) is enabled to allow communication between the backend and frontend.
- This ensures that the frontend can access the backend data without security issues.
- A state variable (
data) is used to store the fetched product data in theHomePage.jsxcomponent. - Use
axiosto send a GET request to the backend API endpoint (http://localhost:8080/product/get-products) to fetch all product data. - The fetched data is stored in the
datastate variable.
- The product data (title, image, description, price, etc.) is dynamically displayed by mapping through the
dataarray. - Each product’s details are passed as props to individual
Cardcomponents.
- The
HomePage.jsxcomponent maps through thedatastate and dynamically generatesCardcomponents for each product. - The relevant product data (title, image, description, price, rating, etc.) is passed to the
Cardcomponent as props.
- The
Card.jsxcomponent is responsible for displaying the product details.- The
Cardcomponent receives props liketitle,image,description,discountedPrice,originalPrice, andrating. - It renders a stylized product card displaying the image, title, description, pricing, and rating.
- The
- When the homepage (
HomePage.jsx) is loaded:- The frontend sends a GET request to the backend to fetch all product data.
- The response data is stored in the state variable
data. - The
datais passed to individualCardcomponents, which display the product details dynamically.
- To run the backend and frontend locally, follow these steps:
-
Start Backend: In the backend project directory, run the following command:
npm run dev
This will start the backend server on
http://localhost:8080. -
Start Frontend: In the frontend project directory, run the following command:
npm run dev
This will start the frontend server on
http://localhost:5173. -
Access Products Page: Open your browser and navigate to
http://localhost:5173to view the products page. The frontend will fetch product data from the backend and display it dynamically.
-
This milestone involves adding functionality to update existing product details. When clicked on "Update" button on the product card, which will pre-fill the form with the current data. After making changes and submitting, the product data will be updated in the MongoDB database.
-
Added
updateProductControllermethod:- Handles updating product details (title, description, rating, prices, quantity, category, and images).
- Checks if the product exists before updating.
- If new images are uploaded, they are processed and uploaded to Cloudinary, replacing the existing images.
- Updates the product in the database using
findByIdAndUpdate.
-
Added
getSingleProductDocumentControllermethod:- Fetches a single product by ID.
- Provides the product details to pre-fill the form on the frontend.
-
Created
PUT /update-products/:idroute:- Maps to the
updateProductControllermethod for handling the product update request. - Accepts product data and images to update the existing product.
- Maps to the
-
Created
GET /get-single/:idroute:- Maps to the
getSingleProductDocumentControllermethod for fetching a single product's details by ID. - Returns the data to auto-fill the update form on the frontend.
- Maps to the
-
Created the Update Form (
UpdateFormcomponent):- Retrieves the current product data by ID using the
GET /get-single/:idroute and auto-fills the form. - Allows users to edit product details (title, description, price, etc.).
- Supports file input for uploading new images.
- Sends a
PUTrequest with the updated product details and images to the backend for updating.
- Retrieves the current product data by ID using the
-
Modified
handleChangefunction:- Updates the state of the form inputs dynamically as the user makes changes.
- Manages form input values for fields such as title, description, discounted price, etc.
-
Implemented image upload handling:
- Allows users to upload new images for the product, appending them to the form data before submission.
-
Updated
handleSubmitfunction:- Collects all the form data and sends it to the backend in the form of
FormData, including any new images or existing image URLs.
- Collects all the form data and sends it to the backend in the form of
-
Created routing for product update page:
- Added a new route
/update-form/:idto handle navigation to the product update form, passing the product ID in the URL. - The route loads the
UpdateFormcomponent, which is responsible for fetching and submitting updated data.
- Added a new route
In Milestone 14, we implemented the functionality for deleting products. This includes a DELETE route in the backend to remove a product from the database by its id. On the frontend, a delete button is added to the product card. When clicked, the product's id is sent to the backend for deletion, and the frontend is updated to reflect the changes by fetching the updated list of products.
-
Added
deleteSingleProductin Product.controller.js:- Fetches the product using the
idfromreq.params. - If the product exists, it deletes the product from the database.
- Returns the updated list of products after deletion.
- If the product doesn't exist, it sends a 404 response with a "Product Not Found" message.
- Fetches the product using the
-
Created
DELETEroute for product deletion:- Adds a
DELETEroute to theproduct.route.jsfile. - The route takes the product
idas a parameter and calls thedeleteSingleProductmethod to handle the deletion.
- Adds a
-
Added delete button in
Cardcomponent:- A delete button (🗑️) is added next to the product information on the product card.
- When clicked, it triggers the
handleDeletefunction, passing the productid.
-
Created
handleDeletefunction:- Sends a
DELETErequest to the backend with the productid. - After successful deletion, the product list is updated by fetching the latest data from the server.
- Sends a
-
Modified
HomePagecomponent:- Calls
handleDeletewhen the delete button is clicked. - Updates the product list on the page by calling the API again after a successful deletion.
- Calls
This project implements a Responsive Navbar Component using React. It facilitates smooth navigation across multiple pages in the application and ensures responsiveness on all screen sizes.
-
Created a Navbar Component with navigation links for:
- Home: The main landing page of the application.
- My Products: A page to view the list of user-added products.
- Add Products: A form to add new products to the application.
- Cart: A page to view items added to the shopping cart.
-
Made the Navbar Responsive:
- Designed a horizontal layout for desktop users.
- Implemented a hamburger menu for mobile users to display navigation links in a dropdown format.
-
Added a Mobile Menu Toggle:
- Used a hamburger icon that opens and closes the navigation menu on smaller screens.
- The menu automatically closes when a link is clicked to enhance the user experience.
-
Highlighted the Active Navigation Link:
- Added dynamic styling to indicate the currently active page.
-
Integrated the Navbar into all application pages:
- Ensured smooth transitions between pages using React Router.
-
Improved the mobile experience:
- Focused on usability by making the menu visually appealing and interactive for smaller screens.
The Single Page Product Details feature displays detailed information about a specific product when a user clicks on it. The page includes the product image gallery, description, price, and action buttons such as "Add to Cart" and "Wishlist."
Key Features:
- Product Image Gallery: Displays product images, where users can click to view a larger version in a modal.
- Product Information: Shows the brand, title, rating, price, and discount information.
- Action Buttons: Allows users to add the product to the cart or wishlist.
- Responsive Layout: Uses Tailwind CSS to create a responsive layout that adapts to different screen sizes.
The Image Modal component displays a larger version of the product images when clicked. It allows users to navigate between images using arrow buttons and view a slideshow of the product's images.
Key Features:
- Image Viewer: Displays the selected product image in full-screen mode.
- Image Navigation: Users can navigate between images using left and right arrow buttons.
- Thumbnail Navigation: Displays small thumbnails of all images at the bottom of the modal to indicate the current image.
The product details page is accessed through the route /product-details/:id, where :id is the unique identifier of the product. The SingleProductPage component is rendered when this route is visited.
This milestone focuses on setting up a foundational structure for the cart functionality and enable adding products to the cart.
-
Cart Schema (
cart.model.js)
Defines the structure for cart data in the database, including fields forproductId,quantity, anduserId. -
Cart Route (
cart.route.js)
Creates the/add-to-cartendpoint and links it to theAddToCartController. -
Cart Controller (
cart.controller.js)
Implements the logic for adding products to the cart:- Validates the
productIdanduserId. - Checks if the product already exists in the user's cart.
- Adds the product to the cart if all conditions are met.
- Validates the
-
Middleware (
jwt-verify.js)
Ensures only authorized users can access cart-related routes by verifying the user token and attaching theuserIdto the request. -
Integration in
app.js
Registers the cart routes under the/cartpath to make the cart-related endpoints functional.
This milestone focuses on creating functionality to retrieve cart data for a user.
-
Cart Route (
cart.route.js)
Adds the/get-user-cart-dataendpoint to fetch the user's cart items, connected to theGetProductsForUsercontroller. -
Cart Controller (
cart.controller.js)
Implements the logic to retrieve all cart items for the authenticated user:- Validates the
userId. - Fetches cart data for the user from the database.
- Validates the
The Cart Page is designed to display products added to a user's cart by fetching data dynamically from the backend. It uses React components and a REST API to create an interactive user interface for managing cart details.
-
CartCard Component:
- Purpose: Renders the UI for individual cart items.
- Props: Accepts product-specific data like
title,image,description,originalPrice,discountedPrice, andid. - Features:
- Displays product details (title, price, description, seller information).
- Links to the product details page using the
id.
-
CartPage Component:
- Purpose: Fetches cart data from the backend and renders a list of
CartCardcomponents. - Hooks Used:
useState: To store the user's cart data.useEffect: To trigger data fetching when the component loads.
- Functionality:
- Retrieves the user's token from
localStoragefor authentication. - Sends a GET request to the
/cart/get-user-cart-dataAPI to fetch cart details. - Maps over the retrieved data to render each cart item using the
CartCardcomponent.
- Retrieves the user's token from
- Purpose: Fetches cart data from the backend and renders a list of
This milestone involves creating a user profile page where the user can view their profile photo, name, email, and addresses. The backend function getUSerData provides the necessary user data to the frontend, which is then displayed using the ProfileCard component.
- Functionality:
getUSerData: This function fetches user data from the database using the user's ID, which is retrieved from the JWT token. It checks for a valid user ID, fetches the user details, and returns them to the frontend. If the user is not found, it responds with an error.
- Purpose: Defines API routes for user actions such as fetching user data.
- Routes:
GET /user-data: Fetches user data after verifying the JWT token.
- Purpose: Defines the main routes of the application.
- Route:
/profile: This route renders theProfilePagecomponent, which displays the user's profile data.
- Purpose: Contains the
ProfileCardcomponent, which is responsible for rendering the user's profile details (name, email, avatar, etc.). - Component Used:
ProfileCard: Displays the user’s profile details, including their avatar, name, email, and address.
- Purpose: Displays detailed user information such as the profile photo, name, email, and address.
- Features:
- Displays the user’s avatar from Cloudinary.
- Shows the user’s name, email, and role.
- Displays a list of the user’s addresses, or shows "No address found" if no address is available.
- Includes an "Edit Profile" button (currently non-functional).
- Fetches user data from the backend using a GET request to
/user/user-dataand displays it accordingly. - Axios is used in
ProfileCard.jsxto make a GET request to fetch the user data from the backend using the stored JWT token for authentication.
- Created address form frontend page and also created the state that will store input address
- Added the /address route in App.jsx
- Endpoint:
POST /user/add-address - Description: This endpoint allows users to add a new address to their profile.
- Required Fields:
city: Name of the city.country: Name of the country.address1: Primary address line.address2: Secondary address line (optional).zipCode: Postal or ZIP code.addressType: Type of address (e.g., home, office).
- Endpoint:
DELETE /user/delete-address/:id - Description: This endpoint deletes an address from the user's profile using the address's unique ID.
The ProfileCard component is used to display the user's profile information, including their addresses. It includes the following sections:
- User Info: Displays the user's avatar, name, email, role, and user ID.
- Address List: Displays all addresses stored for the user, with an option to delete each address.
- The component fetches user data from the backend using the
getUserDatafunction, which makes an API call to/user/user-datawith the user's token.
- The
handleDeleteAddyfunction is used to delete an address by its ID. This function is triggered when the delete button is clicked for a specific address. - The function sends a
DELETErequest to the backend (/user/delete-address/:id) and reloads the user data after the deletion.
The AddAddressController and DeleteAddyController handle adding and deleting addresses in the user's profile.
- This function adds a new address to the
addressarray in the user's profile. - It first verifies the user's existence, then adds the address details to the user's document in the database and saves it.
- This function deletes an address by its ID from the user's
addressarray. - It checks the validity of the address ID and the user before performing the delete operation.
- After deleting the address, it returns the updated user profile.
The user.route.js file contains the routes for adding and deleting addresses.
POST /user/add-address: This route maps to the AddAddressController to add a new address.DELETE /user/delete-address/:id: This route maps to the DeleteAddyController to delete an address by its ID.
- Created a new API endpoint to fetch user addresses.
- Implemented JWT authentication middleware for secure access.
- Validated user ID format before querying the database.
- Retrieved addresses from the database and sent them in the response.
- Handled error cases for invalid users and server issues.
- Added the new route in
user.route.js.
- Added a new route for the "Select Address" page in
App.jsx. - Linked the "Checkout" button in the cart page to navigate to the address selection page.
- Implemented a "Checkout" button using
Linkto navigate to/select-address.
- Fetched user addresses from the backend on component mount using
useEffect. - Retrieved JWT token from
localStorageand included it in API requests. - Stored the fetched addresses in a state variable.
- Passed the addresses to the
AddressListcomponent for rendering.
- Displayed available addresses dynamically.
- Handled cases where no addresses were found.
- Implemented click functionality to select an address.
- Stored the selected address in
localStorage. - Navigated to the order confirmation page upon selection.
- Added a new route for the "Order Confirmation" page in
App.jsx. - Defined a
<Route>for/order-confirmationand linked it toOrderConfirmationcomponent.
- Imported
useEffectanduseStateto handle API calls and manage state. - Fetched user’s cart data from the backend using an API request.
- Retrieved the selected address from
localStorageand stored it in state. - Calculated the total order value by iterating over the cart data.
- Displayed the selected delivery address dynamically.
- Mapped over the cart data to render each product using the
CartCardcomponent. - Added a "Confirm Order" button at the bottom.
- Updated the
CartCardcomponent to correctly display the product image. - Used the first image from the images array instead of the
imageprop.
- Defined Order schema using Mongoose.
- Includes user reference, order items, shipping address, total amount, and order status.
- Order status options:
Processing,Shipped,Delivered,Cancelled. - Stores timestamps for order creation and updates.
- Created a new endpoint (
POST /confirm-order) to handle order creation. - Added JWT authentication middleware (
verifyToken) to secure the endpoint.
- Extracts userId from the request after authentication.
- Validates user existence before processing the order.
- Checks for valid product items in the request body.
- Creates a separate order entry for each product using the same address.
- Stores order details in MongoDB using the Order schema.
- Responds with success or error messages based on the outcome.
- Added
OrderRouterto handle order-related routes. - Ensured environment variables are loaded correctly in non-production environments.
- Connected database and initialized the server.
- Added
GetUserOrdersControllerto:- Validate the
userIdbefore processing. - Check if the user exists in the database.
- Retrieve all orders for the user from the
OrderModel. - Return the fetched data in the response.
- Validate the
- Added route
GET /user-orders-datato fetch all orders for a user. - Ensured JWT authentication is applied to secure the endpoint.
- Updated order-related routes for clarity and structure.
-
POST /orders/confirm-order:
- This endpoint allows users to confirm their orders.
- It creates a new order, associates it with the user, and deletes the items from the cart after successful order creation.
- It expects the following data:
Items: Cart items to be orderedaddress: Shipping addresstotalAmount: Total amount for the order
- Returns a success message with the order details.
-
GET /orders/user-orders-data:
- This endpoint fetches all the orders for a specific user, excluding canceled orders.
- It returns the order details, including the products associated with the order.
-
Order Confirmation Page:
- Users can view the cart and confirm their order by sending a POST request to the
/orders/confirm-orderendpoint. - The page includes the ability to display the cart items and calculate the total amount.
- Users can view the cart and confirm their order by sending a POST request to the
-
Order History Page:
- This page fetches and displays the user's previous orders.
- It sends a GET request to the
/orders/user-orders-dataendpoint and displays the order items and their status.
- The navbar has been updated to include a link to the "Order History" page, allowing users easy access to their past orders.
In this milestone, the functionality for canceling orders has been implemented. Users can cancel their orders directly from the "Orders" page, provided the order hasn't already been canceled. The order status is updated in the backend and displayed accordingly in the frontend.
- CancelOrder Endpoint:
- Created a
PATCH /cancel-orderendpoint that accepts anorderIdand updates the order status to "Cancelled". - Added validation for both the
userIdandorderIdto ensure the correct user is canceling the correct order. - Once the order is canceled, a success response is sent with a confirmation message.
- Created a
-
Order History Page:
- A Cancel Order button has been added for each order.
- The button is only visible if the order's status is not already "Cancelled".
- If an order is canceled, the button disappears and the UI is updated accordingly.
-
Cart Page:
- Made sure the "Checkout" button redirects users to the correct page for order confirmation and adding a shipping address.
-
CartCard Component:
- Added logic to handle the cancelation action. The Cancel Order button triggers a cancelation only when the order is not already canceled.
-
Order History Page Updates:
- Integrated logic to refresh and reflect the updated status of orders after canceling an order.
In this milestone, the Razorpay payment gateway has been integrated into the project. Users can make payments for their orders seamlessly. The backend handles payment processing, while the frontend provides a smooth user experience for completing transactions.
-
Payment Route:
- Created
Payment.route.jsto handle payment-related API endpoints.
- Created
-
Payment Controller:
- Implemented
Payment.controller.jswith logic for creating and processing payments. - API to create an order and process payment.
- Logging added for debugging Razorpay key verification.
- Implemented
-
Payment Model:
- Defined
Payment.model.jsto store payment-related data.
- Defined
-
App Configuration:
- Integrated payment routes into
app.js. - Updated
.envfile with Razorpay API credentials for security.
- Integrated payment routes into
-
Payment SDK Integration:
- Added Razorpay checkout script in
index.html.
- Added Razorpay checkout script in
-
Utility for Razorpay:
- Created
Razorpay.jsto handle payment requests and responses.
- Created
-
Order Confirmation Page:
- Integrated
handlePayfunction to initiate payments. - Displays total amount before proceeding to payment.
- Redirects users to order history upon successful payment.
- Integrated
-
POST
/payment/create-order:- Creates an order in Razorpay with the specified amount.
-
POST
/payment/pay-order:- Processes payment and stores transaction details.
-
GET
/payment/get-razorpay-key:- Fetches Razorpay public key for frontend integration.
In this milestone, we will implement global state management using Redux to store and manage the user's email. This will involve creating a Redux store and user slice, setting up actions for updating the global state, and ensuring that the application components interact with the store correctly. Additionally, we'll wrap the main App component with the Redux Provider to allow global state access across the application.
- Create Redux Store: Use
configureStorefrom@reduxjs/toolkitto create a Redux store. - Set Up Reducer: Define and configure a reducer to manage the user's email state (
userReducer). - Export Store: Export the store for use in other components, ensuring the Redux store is available across the app.
- Define Action Creator: Write an asynchronous function called
setUserEmail, which will accept the user's email as a parameter. - Dispatch Action: Inside the
setUserEmailfunction, dispatch thesetEmailaction to update the user's email in the global state. - Handle State Update: This action will ensure that the user's email is stored correctly in the Redux store.
- Create Initial State: Set up an initial state that includes a default value for the email (empty string).
- Create Slice: Use
createSlicefrom@reduxjs/toolkitto create a slice for managing the user's email state. - Define Reducer: Implement the
setEmailreducer function to update the email in the global state. - Export Action and Reducer: Export the
setEmailaction and the reducer to be used in the store configuration.
- Dispatch Action on Login: Use
useDispatchfromreact-reduxto dispatch thesetUserEmailaction after a successful login. - Store Email in Global State: Pass the email obtained from the form submission to the
setUserEmailaction to store it in the Redux store.
- Wrap
AppwithProvider: Ensure that theAppcomponent is wrapped with theProvidercomponent fromreact-redux. - Pass Redux Store: Pass the configured
store(imported fromsrc/Redux/Store.js) as a prop to theProvidercomponent to make the Redux store available across the app.
In this milestone, we utilize Redux for state management. The user's email is stored in the global state upon login and accessed throughout the application using useSelector.
Uses Redux Toolkit to manage global state. The email is stored globally in the UsersSlice when a user logs in.All pages retrieve user information using useSelector. Ensures data persistence across different components.
-
Fetches cart data from the backend.
-
Stores cart information in a state variable.
-
Uses Redux useSelector to access cart details globally.
-
Displays the number of items in the cart dynamically.
-
Fetches past order data using an API call.
-
Stores ordered products in a state variable.
-
Uses Redux state to track and manage orders across sessions.
-
Retrieves necessary data such as total price, address, and cart items.
-
Uses Redux useSelector to access order details globally.
-
Manages product details using useState.
-
Provides fields for product name, price, quantity, and category.
-
Handles validation for product entry fields.
-
Uses Redux to store product information and retrieve user-related data.
-
Fetches user addresses from an API.
-
Stores all addresses in a state variable.
-
Uses Redux useSelector to access user addresses dynamically.
-
Fetches user profile details using an API request.
-
Displays user information and addresses.
-
Uses Redux to manage and update user data dynamically.
-
Allows users to delete addresses with updated Redux state.
This milestone focuses on improving user authentication by implementing JWT token generation and secure cookie storage.
- Handles User Login – Manages authentication by generating a JWT token.
- JWT Token Generation – Uses the
generateTokenfunction to create a token based on user data. - Secure Cookie Implementation – Stores the JWT token in an HTTP-only, secure, and SameSite-strict cookie.
- Response Update – Sends a structured response containing the login success message and token.
- Prevents XSS & CSRF – Uses
httpOnly: trueto restrict JavaScript access andsameSite: 'Strict'for CSRF protection. - Token Expiry Management – Ensures the token has a defined expiration time.
- Uses Environment Variables – Likely depends on a secret key stored in environment variables for signing JWTs.
- Enhances Security – Implements
secure: trueto ensure cookies are sent only over HTTPS.
-
Generate a JWT token upon successful login and store it securely.
-
Use JWT for authentication and authorization in API requests.
-
Implement token expiration and renewal strategies for security.
- Store JWT tokens in HTTP-only cookies to prevent XSS attacks.
- Ensure proper token invalidation on logout to prevent unauthorized access.