From 8a099ed6a6621c6f692c136a5e16df7bd4275645 Mon Sep 17 00:00:00 2001 From: jalajcodes Date: Sat, 26 Mar 2022 15:50:24 +0530 Subject: [PATCH 1/3] feat: Finished Product Page --- backend/config/db.js | 18 - backend/data/products.js | 185 -- backend/data/users.js | 22 - backend/models/userModel.js | 49 - backend/routes/productRoutes.js | 13 - backend/server.js | 51 - frontend/src/App.js | 51 - frontend/src/Components/Header.js | 113 -- frontend/src/Components/ProductCard.js | 136 -- .../src/Components/ProductsFilterSection.js | 119 -- frontend/src/Components/RangeSlider.js | 87 - .../src/Components/Styles/rangeSlider.scss | 99 -- frontend/src/Contexts/productContext.js | 43 - frontend/src/Pages/Home.js | 94 - frontend/src/Pages/Products.js | 43 - frontend/src/Reducers/productReducer.js | 69 - frontend/src/Styles/Products.scss | 106 -- frontend/src/Utils/productUtils.js | 50 - frontend/src/index.js | 29 - package.json | 33 - yarn.lock | 1524 ----------------- 21 files changed, 2934 deletions(-) delete mode 100644 backend/config/db.js delete mode 100644 backend/data/products.js delete mode 100644 backend/data/users.js delete mode 100644 backend/models/userModel.js delete mode 100644 backend/routes/productRoutes.js delete mode 100644 backend/server.js delete mode 100644 frontend/src/App.js delete mode 100644 frontend/src/Components/Header.js delete mode 100644 frontend/src/Components/ProductCard.js delete mode 100644 frontend/src/Components/ProductsFilterSection.js delete mode 100644 frontend/src/Components/RangeSlider.js delete mode 100644 frontend/src/Components/Styles/rangeSlider.scss delete mode 100644 frontend/src/Contexts/productContext.js delete mode 100644 frontend/src/Pages/Home.js delete mode 100644 frontend/src/Pages/Products.js delete mode 100644 frontend/src/Reducers/productReducer.js delete mode 100644 frontend/src/Styles/Products.scss delete mode 100644 frontend/src/Utils/productUtils.js delete mode 100644 frontend/src/index.js delete mode 100644 package.json delete mode 100644 yarn.lock diff --git a/backend/config/db.js b/backend/config/db.js deleted file mode 100644 index b0341d5..0000000 --- a/backend/config/db.js +++ /dev/null @@ -1,18 +0,0 @@ -import mongoose from "mongoose"; - -const connectDB = async () => { - try { - const URI = - process.env.NODE_ENV === "production" - ? process.env.MONGO_URI_PROD - : process.env.MONGO_URI_DEV; - const conn = await mongoose.connect(URI); - - console.log(`MongoDB Connected: ${conn.connection.host}`.cyan.underline); - } catch (error) { - console.error(`Error: ${error.message}`.red.underline.bold); - process.exit(1); - } -}; - -export default connectDB; diff --git a/backend/data/products.js b/backend/data/products.js deleted file mode 100644 index d063e6b..0000000 --- a/backend/data/products.js +++ /dev/null @@ -1,185 +0,0 @@ -const products = [ - { - name: "Airpods", - image: "/images/airpods.jpg", - description: - "Bluetooth technology lets you connect it with compatible devices wirelessly High-quality AAC audio offers immersive listening experience Built-in microphone allows you to take calls while working", - brand: "Apple", - category: "Electronics", - price: 8999, - countInStock: 3, - rating: 4.5, - numReviews: 4, - }, - { - name: "Fidget Spinner", - image: "/images/toy1.webp", - description: - "This Spinner is a top that combines the best of the Yeezy Boost 350 and the best of the Boost 350 V2. The upper features a full-length, responsive design, while the laces and tongue provide comfort and support.", - brand: "Toy Factory", - category: "Toys", - price: 99, - countInStock: 5, - rating: 2, - numReviews: 1, - }, - { - name: "Cannon EOS 80D DSLR Camera", - image: "/images/camera.jpg", - description: - "Characterized by versatile imaging specs, the Canon EOS 80D further clarifies itself using a pair of robust focusing systems and an intuitive design", - brand: "Cannon", - category: "Electronics", - price: 9299, - countInStock: 5, - rating: 3, - numReviews: 3, - }, - { - name: "NMD R1", - image: "/images/shoe1.jpeg", - description: - "The NMD R1 is a running shoe that combines the best of the NMD and the best of the R1. The upper features a full-length, responsive design, while the laces and tongue provide comfort and support.", - brand: "Nike", - category: "Shoes", - price: 2799, - countInStock: 5, - rating: 2.5, - numReviews: 3, - }, - { - name: "Yeezy Boost 350 V2", - image: "/images/shoe2.jpeg", - description: - "The Yeezy Boost 350 V2 is a shoe that combines the best of the Yeezy Boost 350 and the best of the Boost 350 V2. The upper features a full-length, responsive design, while the laces and tongue provide comfort and support.", - brand: "Nike", - category: "Shoes", - price: 1799, - countInStock: 5, - rating: 3.8, - numReviews: 1, - }, - { - name: "Adidas Joyride Run", - image: "/images/shoe3.jpeg", - description: - "The Adidas Joyride Run is a shoe that combines the best of the Yeezy Boost 350 and the best of the Boost 350 V2. The upper features a full-length, responsive design, while the laces and tongue provide comfort and support.", - brand: "Adidas", - category: "Shoes", - price: 1799, - countInStock: 5, - rating: 4, - numReviews: 1, - }, - { - name: "Sony Playstation 4 Pro White", - image: "/images/playstation.jpg", - description: - "The ultimate home entertainment center starts with PlayStation. Whether you are into gaming, HD movies, television, music", - brand: "Sony", - category: "Electronics", - price: 3999, - countInStock: 10, - rating: 5, - numReviews: 3, - }, - { - name: "Logitech G-Series Gaming Mouse", - image: "/images/mouse.jpg", - description: - "Get a better handle on your games with this Logitech LIGHTSYNC gaming mouse. The six programmable buttons allow customization for a smooth playing experience", - brand: "Logitech", - category: "Electronics", - price: 499, - countInStock: 7, - rating: 5, - numReviews: 2, - }, - { - name: "Amazon Echo Dot 3rd Generation", - image: "/images/alexa.jpg", - description: - "Meet Echo Dot - Our most popular smart speaker with a fabric design. It is our most compact smart speaker that fits perfectly into small space", - brand: "Amazon", - category: "Electronics", - price: 29, - countInStock: 0, - rating: 1, - numReviews: 4, - }, - { - name: "Skechers Classic Sneakers", - image: "/images/shoe4.jpeg", - description: - "The Sketchers Classic Sneakers is a shoe that combines the best of the Yeezy Boost 350 and the best of the Boost 350 V2. The upper features a full-length, responsive design, while the laces and tongue provide comfort and support.", - brand: "Adidas", - category: "Shoes", - price: 1799, - countInStock: 5, - rating: 4, - numReviews: 1, - }, - { - name: "Georgette Fancy Tops", - image: "/images/top1.jpeg", - description: - "The Stylish Tops is a top that combines the best of the Yeezy Boost 350 and the best of the Boost 350 V2. The upper features a full-length, responsive design, while the laces and tongue provide comfort and support.", - brand: "Dolce & Gabbana", - category: "Clothing", - price: 1799, - countInStock: 5, - rating: 3.1, - numReviews: 1, - }, - { - name: "iPhone 11 Pro 256GB Memory", - image: "/images/phone.jpg", - description: - "Introducing the iPhone 11 Pro. A transformative triple-camera system that adds tons of capability without complexity. An unprecedented leap in battery life", - brand: "Apple", - category: "Electronics", - price: 5999, - countInStock: 10, - rating: 3.0, - numReviews: 4, - }, - { - name: "Stylish Tops", - image: "/images/top2.jpeg", - description: - "The Stylish Tops is a top that combines the best of the Yeezy Boost 350 and the best of the Boost 350 V2. The upper features a full-length, responsive design, while the laces and tongue provide comfort and support.", - brand: "Dolce & Gabbana", - category: "Clothing", - price: 1299, - countInStock: 5, - rating: 4.1, - numReviews: 2, - }, - { - name: "Bomber Jacket", - image: "/images/men1.jpeg", - description: - "The Bomber Jacket is a top that combines the best of the Yeezy Boost 350 and the best of the Boost 350 V2. The upper features a full-length, responsive design, while the laces and tongue provide comfort and support.", - brand: "Adidas", - category: "Clothing", - price: 1799, - countInStock: 5, - rating: 1, - numReviews: 1, - }, - - { - name: "Gold Spinner", - image: "/images/toy2.jpeg", - description: - "This Spinner is a top that combines the best of the Yeezy Boost 350 and the best of the Boost 350 V2. The upper features a full-length, responsive design, while the laces and tongue provide comfort and support.", - brand: "Toy Factory", - category: "Toys", - price: 199, - countInStock: 5, - rating: 4, - numReviews: 1, - }, -]; - -export default products; diff --git a/backend/data/users.js b/backend/data/users.js deleted file mode 100644 index a3e18f0..0000000 --- a/backend/data/users.js +++ /dev/null @@ -1,22 +0,0 @@ -import bcrypt from "bcryptjs"; - -const users = [ - { - name: "Jalaj", - email: "jalaj@maxstore.com", - password: bcrypt.hashSync("test1234@", 10), - isAdmin: true, - }, - { - name: "John Doe", - email: "john@maxstore.com", - password: bcrypt.hashSync("test1234", 10), - }, - { - name: "Jane Doe", - email: "Jane@maxstore.com", - password: bcrypt.hashSync("test1234", 10), - }, -]; - -export default users; diff --git a/backend/models/userModel.js b/backend/models/userModel.js deleted file mode 100644 index 1e7abe8..0000000 --- a/backend/models/userModel.js +++ /dev/null @@ -1,49 +0,0 @@ -import mongoose from "mongoose"; -import bcrypt from "bcryptjs"; - -const userSchema = mongoose.Schema( - { - name: { - type: String, - required: true, - }, - email: { - type: String, - required: true, - unique: true, - match: [ - /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/, - "Please fill a valid email address", - ], - }, - password: { - type: String, - required: true, - }, - isAdmin: { - type: Boolean, - required: true, - default: false, - }, - }, - { - timestamps: true, - } -); - -userSchema.methods.matchPassword = async function (enteredPassword) { - return await bcrypt.compare(enteredPassword, this.password); -}; - -userSchema.pre("save", async function (next) { - if (!this.isModified("password")) { - next(); - } - - const salt = await bcrypt.genSalt(10); - this.password = await bcrypt.hash(this.password, salt); -}); - -const User = mongoose.model("User", userSchema); - -export default User; diff --git a/backend/routes/productRoutes.js b/backend/routes/productRoutes.js deleted file mode 100644 index 43134f2..0000000 --- a/backend/routes/productRoutes.js +++ /dev/null @@ -1,13 +0,0 @@ -import express from "express"; -import { - getProducts, - getProductsByIds, - getSingleProduct, -} from "../controllers/productController.js"; -const router = express.Router(); - -router.route("/").get(getProducts); -router.route("/:id").get(getSingleProduct); -router.route("/ids").post(getProductsByIds); - -export default router; diff --git a/backend/server.js b/backend/server.js deleted file mode 100644 index 3b9c08a..0000000 --- a/backend/server.js +++ /dev/null @@ -1,51 +0,0 @@ -import path from "path"; -import express from "express"; -import dotenv from "dotenv"; -import morgan from "morgan"; -import colors from "colors"; -import connectDB from "./config/db.js"; -import productRoutes from "./routes/productRoutes.js"; -import userRoutes from "./routes/userRoutes.js"; -import orderRoutes from "./routes/orderRoutes.js"; -import { notFound, errorHandler } from "./middleware/errorMiddleware.js"; - -dotenv.config(); -connectDB(); - -const app = express(); - -if (process.env.NODE_ENV === "development") { - app.use(morgan("dev")); -} - -app.use(express.json()); - -app.use("/api/products", productRoutes); -app.use("/api/users", userRoutes); -app.use("/api/orders", orderRoutes); - -const __dirname = path.resolve(); - -if (process.env.NODE_ENV === "production") { - app.use(express.static(path.join(__dirname, "/frontend/build"))); - - app.get("*", (req, res) => - res.sendFile(path.resolve(__dirname, "frontend", "build", "index.html")) - ); -} else { - app.get("/", (req, res) => { - res.send("API is running...."); - }); -} - -app.use(notFound); -app.use(errorHandler); - -const PORT = process.env.PORT || 5001; - -app.listen( - PORT, - console.log( - `Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold - ) -); diff --git a/frontend/src/App.js b/frontend/src/App.js deleted file mode 100644 index 6e4be0c..0000000 --- a/frontend/src/App.js +++ /dev/null @@ -1,51 +0,0 @@ -import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; -import Layout from "./Components/Layout"; -import ScrollToTop from "./Components/ScrollTop"; -import Auth from "./Pages/Auth"; -import Home from "./Pages/Home"; -import Profile from "./Pages/Profile"; -import Products from "./Pages/Products"; -import "./Styles/App.scss"; -import { PrivateRoute, RestrictRoute } from "./Components/PrivateRoute"; -import Cart from "./Pages/Cart"; -import Wishlist from "./Pages/Wishlist"; -import NotFound from "./Components/NotFound"; -import SharedCart from "./Pages/SharedCart"; -import ProductPage from "./Pages/Productpage"; -import SearchPage from "./Pages/SearchPage"; -import ShippingScreen from "./Pages/ShippingScreen"; -import PlaceOrder from "./Pages/PlaceOrder"; -import OrderPlaced from "./Pages/OrderPlaced"; -import Orders from "./Pages/Orders"; - -function App() { - return ( - - - - } /> - } /> - } /> - } /> - }> - } /> - - }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - } /> - - - - - ); -} - -export default App; diff --git a/frontend/src/Components/Header.js b/frontend/src/Components/Header.js deleted file mode 100644 index 9cbdc4c..0000000 --- a/frontend/src/Components/Header.js +++ /dev/null @@ -1,113 +0,0 @@ -import { useEffect, useRef, useState } from "react"; -import { Link, useLocation, useNavigate } from "react-router-dom"; -import { useAuth } from "../Contexts/authContext"; -import { useCart } from "../Contexts/cartContext"; -import { useToast } from "../Contexts/toastContext"; -import { getPriceInfo } from "../Utils/cartUtils"; - -const Header = () => { - const { userState, userDispatch, isLoggedIn } = useAuth(); - const navigate = useNavigate(); - const location = useLocation(); - const { addToast } = useToast(); - const { cartItems } = useCart(); - const { qty } = getPriceInfo(cartItems); - const searchRef = useRef(); - const navLinks = useRef(); - const menuIcon = useRef(); - - const handleLogout = (e) => { - e.preventDefault(); - userDispatch({ - type: "USER_LOGOUT", - }); - navigate("/"); - addToast({ type: "success", message: "Logged out successfully" }); - }; - - const handleSearch = (e) => { - e.preventDefault(); - const searchQuery = e.target.elements.search.value; - - if (!searchQuery.trim()) return; - - navigate(`/results/${searchQuery}`); - }; - - const handleMenuClick = (e) => { - navLinks.current.classList.toggle("active"); - }; - - useEffect(() => { - if (location.pathname.includes("results")) return; - searchRef.current.value = ""; - }, [location.pathname]); - - return ( -
- -
- ); -}; - -export default Header; diff --git a/frontend/src/Components/ProductCard.js b/frontend/src/Components/ProductCard.js deleted file mode 100644 index 83dff94..0000000 --- a/frontend/src/Components/ProductCard.js +++ /dev/null @@ -1,136 +0,0 @@ -import ReactTooltip from "react-tooltip"; -import { Link, useLocation, useNavigate } from "react-router-dom"; -import { useCart } from "../Contexts/cartContext"; -import { useWishlist } from "../Contexts/wishlistContext"; -import { useToast } from "../Contexts/toastContext"; -import { useAuth } from "../Contexts/authContext"; - -const ProductCard = ({ - productDetails: { - _id, - name, - price, - image, - rating, - description, - category, - brand, - }, -}) => { - const { addToCart, cartItems } = useCart(); - const { addToast } = useToast(); - const { isLoggedIn } = useAuth(); - const location = useLocation(); - const navigate = useNavigate(); - const wishlistPage = location.pathname.includes("wishlist"); - const { addToWishlist, removeFromWishlist } = useWishlist(); - - const tooltipContent = ` -
    -
  • Brand: ${brand}
  • -
  • Category: ${category}
  • -
  • Rating: ${rating}
  • -
- `; - - const isInCart = cartItems.find((item) => item.product === _id); - - const handleAddToCart = (id, qty) => { - if (isLoggedIn) { - if (isInCart) { - navigate("/cart"); - return; - } - removeFromWishlist(id); - addToCart(id, qty); - addToast({ type: "success", message: "Item added to cart" }); - } else { - navigate("/auth"); - addToast({ type: "error", message: "Please login to add items to cart" }); - } - }; - - const handleWishlistClick = () => { - if (isLoggedIn) { - if (wishlistPage) { - addToast({ type: "success", message: "Item removed from wishlist" }); - removeFromWishlist(_id); - return; - } else { - addToWishlist(_id); - addToast({ type: "success", message: "Item added to wishlist" }); - } - } else { - navigate("/auth"); - addToast({ - type: "error", - message: "Please login to add items to wishlist", - }); - } - }; - - return ( - <> -
-
- - - - - - - - -
-
- - {name} - -

{description}

-
-
- ₹{price} -
-
-