diff --git a/backend/controllers/productController.js b/backend/controllers/productController.js index c5a6c2f..4ceea05 100644 --- a/backend/controllers/productController.js +++ b/backend/controllers/productController.js @@ -184,6 +184,41 @@ exports.getHotProducts = catchAsyncErrors(async (req, res) => { }) }) +// Get Products Bidding Ending Soon +exports.getBidsEndingSoon = catchAsyncErrors(async (req, res) => { + const products = await Product.find({ + status: 'Approved', + bidStatus: 'Live', + }) + .populate({ + path: 'user', + select: 'name avatar.url', + }) + .sort({ endDate: 1 }) + .limit(12) + + res.status(200).json({ + success: true, + products, + }) +}) + +// Get Latest Products +exports.getLatestProducts = catchAsyncErrors(async (req, res) => { + const products = await Product.find({ status: 'Approved', bidStatus: 'Live' }) + .populate({ + path: 'user', + select: 'name avatar.url', + }) + .sort({ createdAt: -1 }) + .limit(12) + + res.status(200).json({ + success: true, + products, + }) +}) + // Get All Products --Admin exports.getAllProductsAdmin = catchAsyncErrors(async (req, res) => { const apiFeature = new ApiFeatures(Product.find({ status: 'Approved' }), req.query) diff --git a/backend/routes/productRoutes.js b/backend/routes/productRoutes.js index e0bef1b..85b2331 100644 --- a/backend/routes/productRoutes.js +++ b/backend/routes/productRoutes.js @@ -11,6 +11,8 @@ const { approveProduct, getApprovalProductsSeller, getHotProducts, + getBidsEndingSoon, + getLatestProducts, } = require('../controllers/productController') const { isAuthenticatedUser, authorizeRole } = require('../middleware/auth') @@ -18,6 +20,8 @@ const router = express.Router() router.route('/products').get(getAllProducts) router.route('/products/hot').get(getHotProducts) +router.route('/products/ending-soon').get(getBidsEndingSoon) +router.route('/products/latest').get(getLatestProducts) router.route('/productsAdmin').get(isAuthenticatedUser, authorizeRole('admin'), getAllProductsAdmin) router.route('/approvalProductsAdmin').get(isAuthenticatedUser, authorizeRole('admin'), getApprovalProductsAdmin) router.route('/approveProduct/:id').put(isAuthenticatedUser, authorizeRole('admin'), approveProduct) diff --git a/frontend/src/pages/Home/Home.jsx b/frontend/src/pages/Home/Home.jsx index 4664dee..abf7067 100644 --- a/frontend/src/pages/Home/Home.jsx +++ b/frontend/src/pages/Home/Home.jsx @@ -10,9 +10,8 @@ import './Home.css' // Sliders import HotProductsSlider from './HotProductsSlider' -import VehiclesSlider from './VehiclesSlider' -import PropertySlider from './PropertySlider' -import MiscProductSlider from './MiscProductSlider' +import ProductsEndingSoonSlider from './ProductsEndingSoonSlider' +import LatestProductsSlider from './LatestProductsSlider' // Utils Import import { @@ -40,9 +39,8 @@ const Home = () => { const [category, setCategory] = useState('') const [hotProducts, setHotProducts] = useState([]) - const [vehicles, setVehicles] = useState([]) - const [properties, setProperties] = useState([]) - const [miscProducts, setMiscProducts] = useState([]) + const [productsEndingSoon, setProductsEndingSoon] = useState([]) + const [latestProducts, setLatestProducts] = useState([]) const [loading, setLoading] = useState(true) const getAllSearchProducts = async () => { @@ -69,24 +67,21 @@ const Home = () => { const fetchProducts = async () => { // dispatch({ type: 'ALL_PRODUCTS_REQUEST' }) try { - const [hotProductsRes, vehiclesRes, propertiesRes, miscRes] = await Promise.all([ + const [hotProductsRes, productsEndingSoonRes, latestProductsRes] = await Promise.all([ customFetch(`/api/v1/products/hot`), - customFetch(`/api/v1/products?category=Vehicles`), - customFetch(`/api/v1/products?category=Property`), - customFetch(`/api/v1/products?category=MiscProducts`), + customFetch(`/api/v1/products/ending-soon`), + customFetch(`/api/v1/products/latest`), ]) - const [hotProductsData, vehiclesData, propertiesData, miscData] = await Promise.all([ + const [hotProductsData, productsEndingSoonData, latestProductsData] = await Promise.all([ hotProductsRes.json(), - vehiclesRes.json(), - propertiesRes.json(), - miscRes.json(), + productsEndingSoonRes.json(), + latestProductsRes.json(), ]) setHotProducts(hotProductsData.products) - setVehicles(vehiclesData.products) - setProperties(propertiesData.products) - setMiscProducts(miscData.products) + setProductsEndingSoon(productsEndingSoonData.products) + setLatestProducts(latestProductsData.products) // dispatch({ // type: 'ALL_PRODUCTS_SUCCESS', // payload: featuredData.products, @@ -105,11 +100,12 @@ const Home = () => { const hotProductsSliderMemo = useMemo(() => , [hotProducts]) - const vehiclesSliderMemo = useMemo(() => , [vehicles]) - - const propertySliderMemo = useMemo(() => , [properties]) + const productsEndingSoonSliderMemo = useMemo( + () => , + [productsEndingSoon] + ) - const miscProductSliderMemo = useMemo(() => , [miscProducts]) + const latestProductsSliderMemo = useMemo(() => , [latestProducts]) if (loading) { return @@ -366,16 +362,12 @@ const Home = () => {
-

Top Vehicles

- {vehiclesSliderMemo} +

Bids About To End

+ {productsEndingSoonSliderMemo}
-

Top Properties

- {propertySliderMemo} -
-
-

Top Miscellaneous Items

- {miscProductSliderMemo} +

Latest Auctions

+ {latestProductsSliderMemo}
) diff --git a/frontend/src/pages/Home/LatestProductsSlider.jsx b/frontend/src/pages/Home/LatestProductsSlider.jsx new file mode 100644 index 0000000..c3e9c5f --- /dev/null +++ b/frontend/src/pages/Home/LatestProductsSlider.jsx @@ -0,0 +1,17 @@ +import React, { useState, useEffect, useMemo } from 'react' +import ProductCard from '../../Components/ProductCard/ProductCard' +import generateId from '../../utils/RandomIdGen' + +const LatestProductsSlider = ({ products }) => { + return ( +
+ {products.map((product) => ( +
+ +
+ ))} +
+ ) +} + +export default LatestProductsSlider diff --git a/frontend/src/pages/Home/MiscProductSlider.jsx b/frontend/src/pages/Home/MiscProductSlider.jsx deleted file mode 100644 index 8197342..0000000 --- a/frontend/src/pages/Home/MiscProductSlider.jsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, { useState, useEffect, useMemo } from 'react' -import ProductCard from '../../Components/ProductCard/ProductCard' -import generateId from '../../utils/RandomIdGen' - -const MiscProductSlider = ({ products }) => { - const [miscProducts, setMiscProducts] = useState([]) - - useEffect(() => { - // Filters misc products by category and sets them to state - setMiscProducts(products.filter((product) => product.category === 'MiscProducts')) - }, [products]) // Correctly listen to changes in products - - // useMemo to shuffle and slice misc products only when they change - const displayedMiscProducts = useMemo(() => { - const shuffleArray = (array) => { - const newArr = array.slice() // Clone to avoid mutation - for (let i = newArr.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)) - ;[newArr[i], newArr[j]] = [newArr[j], newArr[i]] // Swap elements - } - return newArr - } - return shuffleArray(miscProducts).slice(0, 8) // Select the first 4 for display - }, [miscProducts]) - - return ( -
- {displayedMiscProducts.map((miscProduct) => ( -
- -
- ))} -
- ) -} - -export default MiscProductSlider diff --git a/frontend/src/pages/Home/ProductsEndingSoonSlider.jsx b/frontend/src/pages/Home/ProductsEndingSoonSlider.jsx new file mode 100644 index 0000000..5c769c6 --- /dev/null +++ b/frontend/src/pages/Home/ProductsEndingSoonSlider.jsx @@ -0,0 +1,17 @@ +import React, { useState, useEffect, useMemo } from 'react' +import ProductCard from '../../Components/ProductCard/ProductCard' +import generateId from '../../utils/RandomIdGen' + +const ProductsEndingSoonSlider = ({ products }) => { + return ( +
+ {products.map((product) => ( +
+ +
+ ))} +
+ ) +} + +export default ProductsEndingSoonSlider diff --git a/frontend/src/pages/Home/PropertySlider.jsx b/frontend/src/pages/Home/PropertySlider.jsx deleted file mode 100644 index 3ba96a1..0000000 --- a/frontend/src/pages/Home/PropertySlider.jsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, { useState, useEffect, useMemo } from 'react' -import ProductCard from '../../Components/ProductCard/ProductCard' -import generateId from '../../utils/RandomIdGen' - -const PropertySlider = ({ products }) => { - const [properties, setProperties] = useState([]) - - useEffect(() => { - // Filters properties by category and sets them to state - setProperties(products.filter((product) => product.category === 'Property')) - }, [products]) // Add products as a dependency to ensure updates are reflected - - // useMemo to shuffle and slice properties only when they change - const displayedProperties = useMemo(() => { - const shuffleArray = (array) => { - const newArr = array.slice() // Clone to avoid mutation - for (let i = newArr.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)) - ;[newArr[i], newArr[j]] = [newArr[j], newArr[i]] // Swap elements - } - return newArr - } - return shuffleArray(properties).slice(0, 8) // Select the first 4 for display - }, [properties]) - - return ( -
- {displayedProperties.map((property) => ( -
- -
- ))} -
- ) -} - -export default PropertySlider diff --git a/frontend/src/pages/Home/VehiclesSlider.jsx b/frontend/src/pages/Home/VehiclesSlider.jsx deleted file mode 100644 index c144f84..0000000 --- a/frontend/src/pages/Home/VehiclesSlider.jsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, { useState, useEffect, useMemo } from 'react' -import ProductCard from '../../Components/ProductCard/ProductCard' -import generateId from '../../utils/RandomIdGen' - -const VehiclesSlider = ({ products }) => { - const [vehicles, setVehicles] = useState([]) - - useEffect(() => { - const filteredVehicles = products.filter((product) => product.category === 'Vehicles') - setVehicles(filteredVehicles) - }, [products]) // Depend on products so it updates when products change - - // Shuffling and selecting the first 4 vehicles - const shuffledVehicles = useMemo(() => { - const shuffleArray = (array) => { - let newArr = array.slice() - for (let i = newArr.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)) - ;[newArr[i], newArr[j]] = [newArr[j], newArr[i]] // Swap elements - } - return newArr - } - return shuffleArray(vehicles).slice(0, 8) - }, [vehicles]) // Only reshuffle when vehicles array changes - - return ( -
- {shuffledVehicles.map((vehicle) => ( -
- -
- ))} -
- ) -} - -export default VehiclesSlider