diff --git a/client/src/components/Card/ItemCard/ItemCard.css b/client/src/components/Card/ItemCard/ItemCard.css index f55f5d5a..9fde6f5b 100644 --- a/client/src/components/Card/ItemCard/ItemCard.css +++ b/client/src/components/Card/ItemCard/ItemCard.css @@ -1,120 +1,276 @@ +/* Base Card Styling - Modernized */ .product__card__card { - height: 450px; - width: 270px; + width: 100%; + width: 300px; + height: 400px; border: none; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); - border-radius: 20px; - background: rgba(255, 255, 255, 0.95); - backdrop-filter: blur(10px); - transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + border-radius: 16px; + background: #fff; + box-shadow: 0 6px 15px rgba(0, 0, 0, 0.08); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); overflow: hidden; + display: flex; + flex-direction: column; position: relative; + margin: 8px auto 6px; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } .product__card__card:hover { - transform: translateY(-8px); - box-shadow: 0 16px 48px rgba(0, 0, 0, 0.15); -} - -.product__card { - height: 100%; - width: 100%; - position: relative; + transform: scale(1.03); + box-shadow: 0 18px 36px rgba(0, 0, 0, 0.18); } +/* Product Image Section - Enhanced */ .product__image { - height: 70%; + height: 80%; + height: 300px; width: 100%; display: flex; justify-content: center; align-items: center; position: relative; overflow: hidden; - background: linear-gradient(145deg, #fafbfc 0%, #f1f3f6 100%); + background: linear-gradient(135deg, #fff9e6 0%, #fff5f0 100%); + padding: 10px; + transition: all 0.5s ease; +} + +.product__card__card:hover .product__image { + background: linear-gradient(135deg, #fff5e6 0%, #fff0e6 100%); } -.product__image>img { +.product__image > img { max-width: 100%; max-height: 100%; object-fit: contain; - transition: all 0.4s ease; - filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.1)); + transition: transform 0.6s cubic-bezier(0.25, 0.8, 0.25, 1); } -.product__card__card:hover .product__image>img { - transform: scale(1.05); +.product__card__card:hover .product__image > img { + transform: scale(1.08) translateY(-5px); } - -.product__card__detail { - height: 30%; - position: relative; +.product__card__detail > *:last-child { + margin-bottom: 0 !important; +} +/* Rating Overlay - Modernized */ +.rating-overlay { + position: absolute; + bottom: 12px; + right: 12px; + background: rgba(255, 255, 255, 0.95); + padding: 6px 10px; + border-radius: 20px; display: flex; - justify-content: center; align-items: center; - flex-direction: column; - background: linear-gradient(180deg, rgba(255, 255, 255, 0.98) 0%, rgba(248, 250, 252, 0.98) 100%); - padding: 16px 16px 5px 16px; - box-sizing: border-box; + gap: 4px; + font-size: 0.8rem; + font-weight: 600; + color: #FF8C00; + backdrop-filter: blur(5px); + border: 1px solid rgba(255, 140, 0, 0.2); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + z-index: 2; } -.product__card__card a { - color: #2d3748 !important; - text-decoration: none !important; +.rating-overlay .star { + color: #FFD700; + font-size: 1rem; + line-height: 1; } -.product__name { - height: auto; - width: 100%; - display: flex; - justify-content: center; +/* Category Badge - Compact */ +.category-badge { + display: inline-flex; align-items: center; - font-size: 0.95rem; + align-self: flex-start; + background: linear-gradient(135deg, #FFA500 0%, #FF8C00 100%); + color: white; + padding: 2px 10px; + border-radius: 999px; + font-size: 0.62rem; + line-height: 1; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.35px; + box-shadow: 0 2px 6px rgba(255, 140, 0, 0.2); + margin-bottom: 4px; + position: static; + width: auto; + max-width: fit-content; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +/* Product Details Section - Enhanced */ +.product__card__detail { + padding: 14px; + display: flex; + flex-direction: column; + background: white; + flex: 1; + position: relative; + gap: 4px; +} + +/* Product Name - Compact */ +.product__name { + font-size: 0.96rem; font-weight: 600; color: #2d3748; - margin-bottom: 6px; - letter-spacing: 0.3px; + margin: 0 0 2px 0; + line-height: 1.3; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + min-height: 2.4em; + transition: color 0.3s ease; } -.product__description { - height: auto; - width: 100%; - display: flex; - justify-content: center; - align-items: center; - font-size: 0.85rem; - text-align: center; - color: #64748b; - margin-bottom: 12px; - font-weight: 400; +.product__name a { + color: inherit; + text-decoration: none; } +.product__name a:hover { + color: #FF8C00; +} + +/* Price - Compact */ .product__price { - height: auto; - width: fit-content; + font-size: 1.08rem; + font-weight: 700; + color: #2d3748; + margin: 0 0 4px 0; display: flex; - justify-content: center; align-items: center; - font-size: 1.2rem; - font-weight: 700; - color: #1a202c; - z-index: 600; - margin-bottom: 8px; + gap: 6px; } +/* Action Buttons - Compact */ .product__card__action { - width: calc(100% - 20px); - height: 45px; - position: absolute; - bottom: 10px; - left: 10px; - right: 10px; + margin-top: 4px; + padding-top: 6px; + padding-bottom: 6px; + border-top: 1px solid #f3f3f3; display: flex; justify-content: space-between; align-items: center; - flex-direction: row; - padding: 0 12px; - background: linear-gradient(135deg, #FFE26E 30%, #eff468 100%); - border-radius: 12px; - box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); + gap: 8px; +} + +.action-button { + display: flex; + align-items: center; + justify-content: center; + border: none; + border-radius: 8px; + padding: 10px 16px; + font-size: 0.85rem; + font-weight: 600; + cursor: pointer; transition: all 0.3s ease; + outline: none; +} + +.wishlist-button { + background: #fff; + color: #FF8C00; + border: 1px solid #FFE0B2; + min-width: 38px; + height: 38px; + padding: 0; + border-radius: 50%; + margin-bottom: 0; +} + +.wishlist-button:hover { + background: #FFF3E0; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(255, 140, 0, 0.15); +} + +.cart-button { + flex: 1; + background: linear-gradient(135deg, #FFA500 0%, #FF8C00 100%); + color: white; + text-transform: uppercase; + letter-spacing: 0.5px; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + height: 42px; + box-shadow: 0 4px 15px rgba(255, 140, 0, 0.3); + font-size: 0.8rem; + padding: 0 12px; + margin-bottom: 0; +} + +.cart-button:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(255, 140, 0, 0.4); + background: linear-gradient(135deg, #FF8C00 0%, #FF6B00 100%); +} + +.cart-button:active { + transform: translateY(0); +} + +/* Responsive Design */ +@media (max-width: 768px) { + .product__card__card { + max-width: 100%; + min-height: 380px; + margin: 6px 0 4px; + } + + .product__image { + height: 48%; + min-height: 180px; + padding: 8px; + } + + .product__card__detail { + padding: 12px; + gap: 4px; + } + + .product__name { + font-size: 0.94rem; + min-height: 2.3em; + margin: 0 0 2px 0; + } + + .product__price { + font-size: 1rem; + margin: 0 0 4px 0; + } + + .cart-button { + height: 40px; + font-size: 0.78rem; + padding: 0 10px; + } + + .product__card__action { + padding-top: 5px; + padding-bottom: 6px; + border-top: 1px solid #f4f4f4; + } +} + +/* Animation for hover effect */ +@keyframes float { + 0% { transform: translateY(0px); } + 50% { transform: translateY(-5px); } + 100% { transform: translateY(0px); } +} + +.product__card__card:hover { + animation: none; + transform: scale(1.03); } \ No newline at end of file diff --git a/client/src/components/Card/ItemCard/ItemCard.js b/client/src/components/Card/ItemCard/ItemCard.js index 78ba1718..ead284dc 100644 --- a/client/src/components/Card/ItemCard/ItemCard.js +++ b/client/src/components/Card/ItemCard/ItemCard.js @@ -1,124 +1,8 @@ -// import './ItemCard.css'; -// import { useContext, useState } from "react"; -// import { Link } from "react-router-dom"; -// import { CartItemsContext } from "../../../Context/CartItemsContext"; -// import { IconButton } from '@mui/material'; -// import AddShoppingCartIcon from '@mui/icons-material/AddShoppingCart'; -// import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; -// import { WishItemsContext } from '../../../Context/WishItemsContext'; -// import Toaster from '../../Toaster/toaster'; // Import the Toaster component - -// const ItemCard = (props) => { -// const [isHovered, setIsHovered] = useState(false); -// const [showToaster, setShowToaster] = useState(false); -// const [toasterMessage, setToasterMessage] = useState(''); - -// const cartItemsContext = useContext(CartItemsContext); -// const wishItemsContext = useContext(WishItemsContext); - -// const handleAddToWishList = () => { -// wishItemsContext.addItem(props.item); -// setToasterMessage("Your item has been added to wishlist."); -// setShowToaster(true); -// }; - -// // const handleAddToCart = () => { -// // cartItemsContext.addItem(props.item, 1); -// // setToasterMessage("Your item has been added to cart."); -// // setShowToaster(true); -// // }; -// const handleAddToCart = () => { -// const existingItem = cartItemsContext.items.find(item => item._id === props.item._id); - -// const currentQty = existingItem?.quantity ?? 0; -// const newQuantity = currentQty + 1; - -// cartItemsContext.addItem(props.item, 1); - -// setToasterMessage(`"${props.item.name}" added to cart\nQuantity ${newQuantity} added to cart`); -// setShowToaster(true); -// }; - -// const handleCloseToaster = () => { -// setShowToaster(false); -// }; - -// if (!props.item || !props.item.category || !props.item.image || props.item.image.length === 0) { -// return null; // Avoid rendering if item is not defined or missing required properties -// } - -// const getImageUrl = (image) => { -// const url = `https://trendhora-api.onrender.com/public/${props.item.category}/${image.filename}`; -// return url; -// }; - -// return ( -// <> -//
-//
-//
setIsHovered(true)} -// onMouseLeave={() => setIsHovered(false)} -// > -// {isHovered && props.item.image[1] ? -// item : -// item -// } -//
-//
-//
-// -// {props.item.name} -// -//
-//
-// {props.item.description} -//
-//
-// ${props.item.price} -//
-//
-// -// -// -// -// -// -//
-//
-//
-//
- -// {/* Toaster Component */} -// {/* */} -// - -// -// ); -// }; - -// export default ItemCard; - -import "./ItemCard.css"; +import React from 'react'; +import './ItemCard.css'; +import { Link, useNavigate, useParams } from 'react-router-dom'; import { useContext, useState, useEffect } from "react"; -import { Link, useParams } from "react-router-dom"; import { CartItemsContext } from "../../../Context/CartItemsContext"; -import { IconButton } from "@mui/material"; import AddShoppingCartIcon from "@mui/icons-material/AddShoppingCart"; import FavoriteBorderIcon from "@mui/icons-material/FavoriteBorder"; import { WishItemsContext } from "../../../Context/WishItemsContext"; @@ -130,10 +14,33 @@ const ItemCard = (props) => { const [showToaster, setShowToaster] = useState(false); const [toasterTitle, setToasterTitle] = useState(""); const [toasterMessage, setToasterMessage] = useState(""); - const [toasterType, setToasterType] = useState("success"); // success | destructive | warning - + const [toasterType, setToasterType] = useState("success"); const [product, setProduct] = useState(null); const { category, id } = useParams(); + const navigate = useNavigate(); + const cartItemsContext = useContext(CartItemsContext); + const wishItemsContext = useContext(WishItemsContext); + const currentItem = props.item || product; + const itemCategory = currentItem?.category || props.category; + + // ✅ Helper function to check login + const isLoggedIn = () => { + return !!localStorage.getItem("authToken"); // token exist → logged in + }; + + const handleProductClick = (e) => { + e.preventDefault(); + if (!currentItem) return; + const itemId = currentItem._id || currentItem.id; + if (itemCategory && itemId) { + navigate(`/item/${itemCategory}/${itemId}`); + } else { + setToasterTitle("Error"); + setToasterMessage("Could not open product details. Please try again."); + setToasterType("error"); + setShowToaster(true); + } + }; useEffect(() => { if (!props.item && category && id) { @@ -144,142 +51,175 @@ const ItemCard = (props) => { } }, [props.item, category, id]); - const cartItemsContext = useContext(CartItemsContext); - const wishItemsContext = useContext(WishItemsContext); - - const currentItem = props.item || product; - const saveToRecentlyViewed = (product) => { const existing = JSON.parse(localStorage.getItem("recentlyViewed")) || []; const filtered = existing.filter((p) => p.id !== product._id); - - const updated = [ - { - id: product._id, - name: product.name, - image: `https://trendhora-api.onrender.com/public/${product.category}/${product.image[0]?.filename}`, - price: product.price, - category: product.category, - description: product.description, - }, - ...filtered, - ]; - - localStorage.setItem("recentlyViewed", JSON.stringify(updated.slice(0, 6))); + const updated = [product, ...filtered].slice(0, 5); + localStorage.setItem("recentlyViewed", JSON.stringify(updated)); }; - const handleAddToWishList = () => { - const token = localStorage.getItem("token"); - console.log(token); + // ✅ Add to Cart + const handleAddToCart = (e) => { + e.preventDefault(); + e.stopPropagation(); - if (!token) { - setToasterTitle("Login required"); - setToasterMessage("Please log in to add items to your wishlist."); - setToasterType("destructive"); // 🔴 Error toast + if (!isLoggedIn()) { + setToasterTitle("Login Required"); + setToasterMessage("Please login to add items to cart."); + setToasterType("error"); setShowToaster(true); + // navigate("/login"); // redirect to login page return; } - wishItemsContext.addItem(currentItem); - setToasterTitle(`Added "${currentItem.name}" to wishlist`); - setToasterMessage("Your item has been added to wishlist."); - setToasterType("success"); // ✅ Success toast - setShowToaster(true); + if (currentItem) { + const normalized = { + ...currentItem, + _id: currentItem._id || currentItem.id, + category: itemCategory, + }; + cartItemsContext.addItemToCart(normalized); + setToasterTitle("Success"); + setToasterMessage("Item added to cart!"); + setToasterType("success"); + setShowToaster(true); + } }; - const handleAddToCart = () => { - cartItemsContext.addItem({ ...currentItem, quantity: 1 }); - const cartItem = cartItemsContext.items.find( - (i) => i._id === currentItem._id - ); - const updatedQty = cartItem ? cartItem.quantity : 1; - setToasterTitle(`"${currentItem.name}" added to cart`); - setToasterMessage(`Quantity: ${updatedQty || 1}`); - setToasterType("success"); // ✅ Success toast - setShowToaster(true); + // ✅ Add to Wishlist + const handleAddToWishList = (e) => { + e.preventDefault(); + e.stopPropagation(); + + if (!isLoggedIn()) { + setToasterTitle("Login Required"); + setToasterMessage("Please login to add items to wishlist."); + setToasterType("error"); + setShowToaster(true); + // navigate("/login"); + + return; + } + + if (currentItem) { + const normalized = { + ...currentItem, + _id: currentItem._id || currentItem.id, + category: itemCategory, + }; + wishItemsContext.addItemToWishList(normalized); + setToasterTitle("Success"); + setToasterMessage("Item added to wishlist!"); + setToasterType("success"); + setShowToaster(true); + } }; const handleCloseToaster = () => { setShowToaster(false); }; - if ( - !currentItem || - !currentItem.category || - !currentItem.image || - currentItem.image.length === 0 - ) { + if (!currentItem || !itemCategory || !currentItem.image || currentItem.image.length === 0) { return null; } const getImageUrl = (image) => { - if (image.filename) { - return `https://trendhora-api.onrender.com/public/${currentItem.category}/${image.filename}`; - } else if (typeof image === "string") { - return image; + if (!image) return ''; + return typeof image === 'string' + ? image + : `https://trendhora-api.onrender.com/public/${itemCategory}/${image.filename}`; + }; + + const imageUrl = getImageUrl(currentItem.image[0]); + const hoverImageUrl = + Array.isArray(currentItem.image) && currentItem.image[1] + ? getImageUrl(currentItem.image[1]) + : imageUrl; + + const getConsistentRating = (item) => { + const key = (item?._id || item?.id || item?.name || "").toString(); + if (!key) return 4.5; + let hash = 0; + for (let i = 0; i < key.length; i++) { + hash = (hash * 31 + key.charCodeAt(i)) | 0; } - return ""; + const min = 38; + const max = 50; + const range = max - min + 1; + const val = Math.abs(hash % range) + min; + return val / 10; }; + const ratingValue = + typeof currentItem.rating === "number" + ? currentItem.rating + : getConsistentRating(currentItem); + + const itemId = currentItem._id || currentItem.id; + const detailPath = itemCategory && itemId ? `/item/${itemCategory}/${itemId}` : "#"; + return ( - <> -
-
- -
setIsHovered(true)} - onMouseLeave={() => setIsHovered(false)} - > - {isHovered && currentItem.image[1] ? ( - item - ) : ( - item - )} -
+
setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + style={{ cursor: "pointer" }} + > +
+ {currentItem.name { + e.target.onerror = null; + e.target.src = "/path-to-placeholder-image.png"; + }} + /> +
+ + {ratingValue.toFixed(1)}/5.0 +
+
+
+ {itemCategory} +
+ { + if (detailPath === "#") { + e.preventDefault(); + setToasterTitle("Error"); + setToasterMessage("Could not open product details. Please try again."); + setToasterType("error"); + setShowToaster(true); + return; + } + saveToRecentlyViewed(currentItem); + }} + > + {currentItem.name} -
-
- saveToRecentlyViewed(currentItem)} - > - {currentItem.name} - -
-
- {currentItem.description} -
-
- ${currentItem.price} -
-
- - - - - - -
-
+
+
${currentItem.price}
+
+ + + +
{ message={toasterMessage} isVisible={showToaster} onClose={handleCloseToaster} - type={toasterType} // ✅ Uses dynamic type + type={toasterType} duration={1000} /> - +
); }; diff --git a/client/src/components/Category/Category.css b/client/src/components/Category/Category.css index 02bb2373..6f057c44 100644 --- a/client/src/components/Category/Category.css +++ b/client/src/components/Category/Category.css @@ -1,9 +1,9 @@ - - .category__container { - height: auto; + position: relative; + min-height: 100vh; width: 100%; margin-top:0rem; + padding-bottom: 120px; /* Space for the button */ } .category { @@ -58,41 +58,107 @@ margin: 4px; } .category__card__container { - height: auto; width: 100%; - display: flex; - justify-content: center; - align-items: center; - margin-top: 2rem; + padding: 1rem 0; + margin: 1rem 0; } .category__product__card { - height: auto; - width: 95%; - display: flex; + width: 90%; + margin: 0 auto; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 2rem; justify-content: center; + + padding: 1rem 0; +======= flex-wrap: wrap; gap: 50px; + } -.show__more__action { +/* Ensure consistent card sizing */ +.category__product__card > * { width: 100%; - height: 200px; - bottom: 0%; + margin: 0; +} + +/* Responsive adjustments */ +@media (max-width: 1200px) { + .category__product__card { + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + gap: 1.5rem; + } +} + +@media (max-width: 768px) { + .category__product__card { + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 1.25rem; + width: 95%; + } +} + +@media (max-width: 480px) { + .category__product__card { + grid-template-columns: 1fr; + gap: 1.5rem; + max-width: 320px; + margin: 0 auto; + } +} + +.show__more__action { + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 2rem 0; display: flex; justify-content: center; align-items: center; + background: linear-gradient(to top, rgba(255,255,255,1) 0%, rgba(255,255,255,0.9) 50%, rgba(255,255,255,0) 100%); + z-index: 2; +} + +/* Dark mode gradient */ +.dark-mode .show__more__action { + background: linear-gradient(to top, rgba(0,0,0,1) 0%, rgba(0,0,0,0.9) 50%, rgba(0,0,0,0) 100%); } .show__more__button { - width: 200px; - height: 25%; - border-radius: 20px; + min-width: 200px; + padding: 0.75rem 2rem; + border-radius: 25px; font-size: 1rem; + font-weight: 600; background-color: #FFE26E; - border-color: #FFE26E; - border-style: dashed; - font-weight:bold; + border: 2px solid #FFE26E; + color: #1a1a1a; + cursor: pointer; + transition: all 0.3s ease; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.show__more__button:hover { + background-color: #f5d84e; + border-color: #f5d84e; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(255, 214, 0, 0.3); +} + +/* Dark mode styles */ +.dark-mode .show__more__button { + background-color: #2d2d2d; + border-color: #444; + color: #ffffff; +} + +.dark-mode .show__more__button:hover { + background-color: #3a3a3a; + border-color: #555; } /* Dark mode: black background for category container */ diff --git a/client/src/components/Featured/Items/FeaturedItems.css b/client/src/components/Featured/Items/FeaturedItems.css index 949e3c73..d0248a96 100644 --- a/client/src/components/Featured/Items/FeaturedItems.css +++ b/client/src/components/Featured/Items/FeaturedItems.css @@ -1,55 +1,81 @@ .featured__products__container { width: 100%; - height: auto; - min-height: 25rem; - margin-top: 30px; + min-height: 100vh; + padding: 4rem 0; background-color: var(--bg-primary); + transition: all 0.3s ease; } -.featured__products{ - height: auto; - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - padding-top: 50px; +.featured__products { + max-width: 1400px; + margin: 0 auto; + padding: 0 2rem; } .featured__products__header { - width: 92%; - display: flex; - align-items: flex-start; - flex-direction: row; text-align: center; + margin-bottom: 3rem; + position: relative; + padding-bottom: 1.5rem; } .featured__items__header__big { - font-size: 2rem; - font-weight: 600; - color: #000000; + font-size: 2.5rem; + font-weight: 700; + color: var(--text-primary); + margin-bottom: 1rem; + position: relative; + display: inline-block; +} + +.featured__items__header__big::after { + content: ''; + position: absolute; + width: 80px; + height: 4px; + background: var(--accent-color); + bottom: -10px; + left: 50%; + transform: translateX(-50%); + border-radius: 2px; } .featured__header__small { - margin: auto 20px; - text-decoration: none; + display: inline-flex; + align-items: center; + margin-top: 1.5rem; color: var(--text-secondary); + text-decoration: none; + font-weight: 500; + transition: all 0.3s ease; + background: var(--bg-secondary); + padding: 0.6rem 1.5rem; + border-radius: 50px; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); } -.featured__header__small:hover{ +.featured__header__small:hover { color: var(--accent-color); + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1); +} + +.featured__header__small svg { + margin-left: 0.5rem; + transition: transform 0.3s ease; } -.featured__products__header__line { - width: 150px; - height: 6px; - background-color: var(--accent-color); - align-self: flex-start; - margin-left: 50px; - border-radius: 25px; +.featured__header__small:hover svg { + transform: translateX(5px); } .featured__products__card__container { + + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 2rem; + padding: 1rem 0; margin-top: 20px; padding: 30px; width: 100%; @@ -59,20 +85,67 @@ align-items: center; flex-wrap: wrap; gap: 50px; + } -/* Dark mode: black background for featured items container */ +/* Dark Mode Styles */ .dark-mode .featured__products__container { - background-color: #000000; + background-color: #121212; } -/* Dark mode: white text for featured items header */ .dark-mode .featured__items__header__big { color: #ffffff; } -/* Add soft white shadow to item cards in dark mode */ -.dark-mode .featured__products__card__container .card { - box-shadow: 0 2px 8px rgba(255, 255, 255, 0.1); - background-color: #ffffff; +.dark-mode .featured__header__small { + background: #1e1e1e; + color: #e0e0e0; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); +} + +.dark-mode .featured__header__small:hover { + color: var(--accent-color); + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3); +} + +/* Responsive Design */ +@media (max-width: 1200px) { + .featured__products__card__container { + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + } +} + +@media (max-width: 768px) { + .featured__products { + padding: 0 1.5rem; + } + + .featured__items__header__big { + font-size: 2rem; + } + + .featured__products__card__container { + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 1.5rem; + } +} + +@media (max-width: 480px) { + .featured__products { + padding: 0 1rem; + } + + .featured__items__header__big { + font-size: 1.75rem; + } + + .featured__products__card__container { + grid-template-columns: 1fr 1fr; + gap: 1rem; + } + + .featured__header__small { + padding: 0.5rem 1.2rem; + font-size: 0.9rem; + } } diff --git a/client/src/components/Featured/Items/FetauredItems.js b/client/src/components/Featured/Items/FetauredItems.js index 9d8c4901..f999d3ce 100644 --- a/client/src/components/Featured/Items/FetauredItems.js +++ b/client/src/components/Featured/Items/FetauredItems.js @@ -4,33 +4,46 @@ import ItemCard from '../../Card/ItemCard/ItemCard'; import ReactLoading from 'react-loading'; import './FeaturedItems.css' -const FeaturedItems = (props) => { +const FeaturedItems = ({ items }) => { + // Ensure we have items before trying to access them + const featuredItems = items ? [ + items[0], + items[4], + items[10], + items[20], + items[16], + items[5], + items[13], + items[23] + ].filter(Boolean) : []; + return ( -
-

Featured Items

Show all +

Featured Items

+ + View All + +
-
-
- {!props.items && } - { props.items && -
- - - - - - - - -
- } + +
+ {!items ? ( +
+ +
+ ) : featuredItems.length > 0 ? ( + featuredItems.map((item, index) => ( + + )) + ) : ( +

No featured items available

+ )}
- ); + ); } export default FeaturedItems; \ No newline at end of file diff --git a/client/src/components/Nav/Container/Container.js b/client/src/components/Nav/Container/Container.js index d5bab42e..989bd7e0 100644 --- a/client/src/components/Nav/Container/Container.js +++ b/client/src/components/Nav/Container/Container.js @@ -1,13 +1,13 @@ -import Control from '../Controls/Control'; -import DrawerNav from '../DrawerNav/DrawerNav'; -import NavBrand from '../Nav-Brand/Navbrand'; -import Form from '../Search-Bar/Form'; -import './Container.css'; -import Box from '@mui/material/Box'; -import useMediaQuery from '@mui/material/useMediaQuery'; +import Control from "../Controls/Control"; +import DrawerNav from "../DrawerNav/DrawerNav"; +import NavBrand from "../Nav-Brand/Navbrand"; +import Form from "../Search-Bar/Form"; +import "./Container.css"; +// import Box from '@mui/material/Box'; +import useMediaQuery from "@mui/material/useMediaQuery"; const Navtop = () => { - const isSmallScreen = useMediaQuery('(max-width:768px)'); + const isSmallScreen = useMediaQuery("(max-width:768px)"); return (
@@ -28,7 +28,7 @@ const Navtop = () => {
)} - + {/* Mobile Hamburger */} {isSmallScreen && (
@@ -37,17 +37,15 @@ const Navtop = () => { )}
{isSmallScreen && ( -
+
-
- )} - - +
+ )}
); }; diff --git a/client/src/components/Shop/Container/ShopCategory.css b/client/src/components/Shop/Container/ShopCategory.css index 8ecfac19..c39382de 100644 --- a/client/src/components/Shop/Container/ShopCategory.css +++ b/client/src/components/Shop/Container/ShopCategory.css @@ -1,81 +1,533 @@ - +/* Modern Shop Category Container */ .shop__category__container { - height: 100%; - width:100%; - display: flex; - justify-content: center; - flex-direction: column; - align-items: center; - margin-top: 0rem; + width: 100%; + max-width: 1440px; + margin: 0 auto; + padding: 2rem 1.5rem; + display: flex; + flex-direction: column; + gap: 2rem; } +/* Header Styling */ .shop__category__header { - width: 90%; - height: 150px; - display: flex; - justify-content: flex-start; - align-items: center; - margin: 20px auto; + width: 100%; + margin-bottom: 1rem; } -.shop__category__header__big { - height: auto; +.shop__category__head h2 { + font-size: 2rem; + font-weight: 700; + color: #1a1a1a; + margin: 0 0 0.5rem 0; + text-transform: capitalize; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; + letter-spacing: -0.5px; } .shop__category__header__line { - width: 120px; - height: 6px; - background-color: #FFE26E; - align-self: flex-start; - border-radius: 25px; + width: 80px; + height: 4px; + background: linear-gradient(90deg, #20c997, #1aa87a); + border-radius: 2px; + transition: width 0.3s ease; +} + +.shop__category__header:hover .shop__category__header__line { + width: 100px; +} + +/* Filter Section */ +.shop__category__filters { + display: flex; + flex-wrap: wrap; + gap: 1.5rem; + background: #ffffff; + padding: 1.5rem; + border-radius: 12px; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06); + margin-bottom: 1.5rem; + border: 1px solid #f0f0f0; +} + +.filter__group { + display: flex; + flex-direction: column; + gap: 0.5rem; + min-width: 200px; + flex: 1; +} + +.filter__group label { + font-size: 0.85rem; + font-weight: 600; + color: #555; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.filter__group select, +.filter__group input { + padding: 0.75rem 1rem; + border: 1px solid #e0e0e0; + border-radius: 8px; + font-size: 0.95rem; + background: #fff; + color: #333; + transition: all 0.2s ease; + width: 100%; +} + +/* Enhanced Dropdown Styling */ +.filter__group select { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 1rem center; + background-size: 1rem; + padding: 0.75rem 1rem; + padding-right: 2.5rem; + border: 1px solid #e0e0e0; + border-radius: 8px; + font-size: 0.95rem; + color: #333; + background-color: #fff; + cursor: pointer; + transition: all 0.2s ease; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.filter__group select:hover { + border-color: #b3b3b3; +} + +.filter__group select:focus { + outline: none; + border-color: #20c997; + box-shadow: 0 0 0 3px rgba(32, 201, 151, 0.2); +} + +.filter__group select:focus-visible { + outline: 2px solid #20c997; + outline-offset: 2px; +} + +.filter__group input:focus { + outline: none; + border-color: #20c997; + box-shadow: 0 0 0 2px rgba(32, 201, 151, 0.2); +} + +.filter__group input:focus-visible { + outline: 2px solid #20c997; + outline-offset: 2px; +} + +/* Price Inputs */ +.price__inputs { + display: flex; + align-items: center; + gap: 0.75rem; + width: 100%; +} + +.price__input { + flex: 1; + min-width: 100px; + padding: 0.75rem 1rem; + border: 1px solid #e0e0e0; + border-radius: 8px; + background: #fff; + color: #333; + transition: all 0.2s ease; +} + +.price__input:focus { + outline: none; + border-color: #20c997; + box-shadow: 0 0 0 2px rgba(32, 201, 151, 0.2); +} + +.price__input:focus-visible { + outline: 2px solid #20c997; + outline-offset: 2px; +} + +/* Improved Button Styling */ +.apply__filters, +.reset__filters { + padding: 0.75rem 1.5rem; + border: none; + border-radius: 8px; + font-size: 0.95rem; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + text-transform: uppercase; + letter-spacing: 0.5px; + height: fit-content; + align-self: flex-end; + margin-top: 1.5rem; + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + +.apply__filters { + background: #20c997; + color: white; + box-shadow: 0 2px 4px rgba(32, 201, 151, 0.3); +} + +.apply__filters:hover { + background: #1aa87a; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(32, 201, 151, 0.3); +} + +.apply__filters:active { + transform: translateY(0); +} + +.apply__filters:focus-visible { + outline: 2px solid #20c997; + outline-offset: 2px; +} + +.reset__filters { + background: #f5f5f5; + color: #666; + border: 1px solid #e0e0e0; + margin-right: 0.5rem; +} + +.reset__filters:hover { + background: #eaeaea; + border-color: #d4d4d4; + color: #333; +} + +.reset__filters:active { + background: #e0e0e0; +} + +.reset__filters:focus-visible { + outline: 2px solid #20c997; + outline-offset: 2px; +} + +/* No Results Message */ +.no-results { + grid-column: 1 / -1; + text-align: center; + padding: 3rem 1rem; + background: #f9f9f9; + border-radius: 12px; + margin: 1rem 0; +} + +.no-results p { + color: #666; + font-size: 1.1rem; + margin-bottom: 1.5rem; +} + +.no-results .reset__filters { + background: #20c997; + color: white; + border: none; + padding: 0.75rem 1.5rem; + border-radius: 8px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.no-results .reset__filters:hover { + background: #1aa87a; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +/* Dark Mode for No Results */ +.dark .no-results { + background: #1e1e1e; + border: 1px solid #333; +} + +.dark .no-results p { + color: #b0b0b0; +} + +.dark .no-results .reset__filters { + background: #20c997; + color: white; } +.dark .no-results .reset__filters:hover { + background: #1aa87a; +} + +/* Dark Theme */ +.dark .shop__category__container { + background-color: #3e3c3c00; + color: #f5f5f5; +} + +.dark .shop__category__head h2 { + color: #f5f5f5; +} + +.dark .shop__category__filters { + background: #1e1e1e; + border-color: #333; + box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3); +} + +.dark .filter__group label { + color: #b0b0b0; +} + +.dark .filter__group select, +.dark .filter__group input { + background-color: #2d2d2d; + border-color: #444; + color: #f0f0f0; +} + +.dark .filter__group select { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23b0b0b0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E"); +} + +.dark .filter__group select:hover, +.dark .filter__group input:hover { + border-color: #666; +} + +.dark .filter__group select:focus, +.dark .filter__group input:focus { + border-color: #20c997; + box-shadow: 0 0 0 3px rgba(32, 201, 151, 0.3); +} + +.dark .price__input { + background-color: #2d2d2d; + border-color: #444; + color: #f0f0f0; +} + +.dark .price__input::placeholder { + color: #888; +} + +.dark .price__inputs span { + color: #b0b0b0; +} + +.dark .apply__filters { + background: #20c997; + color: #fff; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); +} + +.dark .apply__filters:hover { + background: #1aa87a; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3); +} + +.dark .reset__filters { + background: #2d2d2d; + border-color: #444; + color: #b0b0b0; +} + +.dark .reset__filters:hover { + background: #5b5353; + border-color: #555; + color: #fff; +} + +/* Product Card Dark Theme */ +.dark .shop__category__product__card .product__card__card { + background: #1e1e1e; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); + border: 1px solid #333; +} + +.dark .shop__category__product__card .product__card__card:hover { + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3); + border-color: #444; +} + +/* Text colors in dark mode */ +.dark .product__card__title, +.dark .product__card__price { + color: #f5f5f5; +} + +.dark .product__card__category { + color: #b0b0b0; +} + +/* Responsive adjustments for dark theme */ +@media (max-width: 768px) { + .dark .shop__category__filters { + padding: 1rem; + } + + .dark .filter__group { + min-width: 100%; + } +} + +/* Animation for dark mode */ +@keyframes fadeInDark { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.dark .shop__category__product__card > * { + animation: fadeInDark 0.4s ease-out forwards; +} + +/* Product Grid */ .shop__category__card__container { - height: auto; - width: 100%; - padding: 20px; + width: 100%; + padding: 0; } .shop__category__product__card { + + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 2rem; + width: 100%; + margin: 0; + padding: 1rem 0; + height: auto; width: 95%; display: flex; justify-content: center; flex-wrap: wrap; gap : 50px; + } -.shop__category__product__card { - height: auto; - width: 100%; +/* Card Styling +.shop__category__product__card .product__card__card { + width: 100%; + height: 100%; + border-radius: 12px; + overflow: hidden; + background: #ffffff; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.shop__category__product__card .product__card__card:hover { + transform: translateY(-4px); + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1); +} */ + +.shop__category__product__card { overflow: visible; } +/* Responsive Design */ +@media (max-width: 1200px) { + .shop__category__product__card { + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + gap: 1.5rem; + } } -/* Dark mode: black background for shop category container */ -.dark-mode .shop__category__container { - background-color: #000000; +@media (max-width: 992px) { + .shop__category__filters { + flex-direction: column; + gap: 1rem; + } + + .filter__group { + width: 100%; + } + + .apply__filters, + .reset__filters { + width: 100%; + margin-top: 0.5rem; + } } -/* Dark mode: white text for shop category headers */ -.dark-mode .shop__category__head h2 { - color: #ffffff; +@media (max-width: 768px) { + .shop__category__container { + padding: 1.5rem 1rem; + } + + .shop__category__product__card { + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 1.25rem; + } + + .price__inputs { + flex-direction: column; + gap: 0.5rem; + } + + .price__input { + width: 100%; + } + + .shop__category__filters { + flex-direction: column; + gap: 1rem; + } + + .filter__group { + width: 100%; + min-width: 100%; + } + + .apply__filters, + .reset__filters { + width: 100%; + margin-top: 0.5rem; + justify-content: center; + } } -/* Dark mode: white text for any filter or sort elements in shop */ -.dark-mode .shop__category__container .show__filter, -.dark-mode .shop__category__container .filter__by { - color: #ffffff !important; +@media (max-width: 480px) { + .shop__category__product__card { + grid-template-columns: 1fr; + gap: 1.5rem; + } + + .shop__category__head h2 { + font-size: 1.75rem; + } } -/* Dark mode: white text for any text elements in shop category */ -.dark-mode .shop__category__container label, -.dark-mode .shop__category__container span, -.dark-mode .shop__category__container div { - color: #ffffff !important; +/* Animations */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } } -/* Dark mode: white text for any select or option elements in shop */ -.dark-mode .shop__category__container select, -.dark-mode .shop__category__container option { - color: #ffffff !important; - background-color: #2d2d2d !important; -} \ No newline at end of file + +.shop__category__product__card > *:nth-child(1) { animation-delay: 0.1s; } +.shop__category__product__card > *:nth-child(2) { animation-delay: 0.15s; } +.shop__category__product__card > *:nth-child(3) { animation-delay: 0.2s; } +.shop__category__product__card > *:nth-child(4) { animation-delay: 0.25s; } +.shop__category__product__card > *:nth-child(5) { animation-delay: 0.3s; } +.shop__category__product__card > *:nth-child(n+6) { animation-delay: 0.35s; } \ No newline at end of file diff --git a/client/src/components/Shop/Container/ShopCategory.js b/client/src/components/Shop/Container/ShopCategory.js index 87ea2222..07936fea 100644 --- a/client/src/components/Shop/Container/ShopCategory.js +++ b/client/src/components/Shop/Container/ShopCategory.js @@ -1,7 +1,75 @@ +import { useState, useEffect } from 'react'; import ItemCard from "../../Card/ItemCard/ItemCard"; import "./ShopCategory.css"; const ShopCategory = (props) => { + const [filters, setFilters] = useState({ + minPrice: '', + maxPrice: '', + sort: 'newest', + }); + const [filteredItems, setFilteredItems] = useState(props.items || []); + const [isFilterApplied, setIsFilterApplied] = useState(false); + + // Apply filters when component mounts or items change + useEffect(() => { + applyFilters(); + }, [props.items]); + + const handleFilterChange = (e) => { + const { name, value } = e.target; + setFilters(prev => ({ + ...prev, + [name]: value + })); + }; + + const applyFilters = (e) => { + e?.preventDefault(); + + let result = [...(props.items || [])]; + + // Apply price filter + if (filters.minPrice) { + result = result.filter(item => + parseFloat(item.price) >= parseFloat(filters.minPrice) + ); + } + + if (filters.maxPrice) { + result = result.filter(item => + parseFloat(item.price) <= parseFloat(filters.maxPrice) + ); + } + + // Apply sorting + if (filters.sort === 'price-low') { + result.sort((a, b) => parseFloat(a.price) - parseFloat(b.price)); + } else if (filters.sort === 'price-high') { + result.sort((a, b) => parseFloat(b.price) - parseFloat(a.price)); + } else if (filters.sort === 'newest') { + // Assuming newer items have higher IDs (adjust according to your data structure) + result.sort((a, b) => (b.id || 0) - (a.id || 0)); + } else if (filters.sort === 'popularity') { + // Assuming you have a 'popularity' field in your items + result.sort((a, b) => (b.popularity || 0) - (a.popularity || 0)); + } + + setFilteredItems(result); + setIsFilterApplied(true); + }; + + const resetFilters = (e) => { + e?.preventDefault(); + setFilters({ + minPrice: '', + maxPrice: '', + sort: 'newest', + }); + setFilteredItems(props.items || []); + setIsFilterApplied(false); + }; + return (
@@ -12,11 +80,88 @@ const ShopCategory = (props) => {
+ + {/* Filter Section */} + +
+ + +
+ +
+ +
+ + - + +
+
+ +
+ + + +
+ +
- {props.items.map((data, indx) => ( - - ))} + {filteredItems.length > 0 ? ( + filteredItems.map((data, indx) => ( + + )) + ) : ( +
+

No products match your filters. Try adjusting your criteria.

+ +
+ )}
diff --git a/client/src/components/Shop/Shop.css b/client/src/components/Shop/Shop.css index 2c09b3f2..0344e409 100644 --- a/client/src/components/Shop/Shop.css +++ b/client/src/components/Shop/Shop.css @@ -1,13 +1,156 @@ +/* Modern Shop Container */ .shop__contianer { - height: auto; - min-height: 80vh; width: 100%; + min-height: 100vh; display: flex; - flex-direction: column; - margin-top: 0rem; + flex-direction: column; + gap: 2rem; + padding: 1rem 0; + background-color: #f9f9f9; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; + color: #1a1a1a; + line-height: 1.6; } -/* Dark mode: black background for shop container */ +/* Shop Header */ +.shop__header { + text-align: center; + margin-bottom: 3rem; + padding: 0 1.5rem; +} + +.shop__title { + font-size: 2.5rem; + font-weight: 700; + margin-bottom: 1rem; + color: #1a1a1a; + letter-spacing: -0.5px; +} + +.shop__subtitle { + font-size: 1.125rem; + color: #666; + max-width: 700px; + margin: 0 auto; + font-weight: 400; +} + +/* Shop Content */ +.shop__content { + width: 100%; + max-width: 1440px; + margin: 0 auto; + padding: 0 1.5rem; + animation: fadeIn 0.5s ease-out forwards; +} + +/* Category Section */ +.category-section { + margin-bottom: 4rem; +} + +/* Responsive Adjustments */ +@media (max-width: 1024px) { + .shop__title { + font-size: 2.25rem; + } + + .shop__subtitle { + font-size: 1.0625rem; + } +} + +@media (max-width: 768px) { + .shop__contianer { + padding: 1.5rem 0; + } + + .shop__title { + font-size: 2rem; + } + + .shop__header { + margin-bottom: 2rem; + } +} + +@media (max-width: 480px) { + .shop__title { + font-size: 1.75rem; + } + + .shop__subtitle { + font-size: 1rem; + } + + .shop__contianer { + padding: 1rem 0; + } +} + +/* Dark Mode Styles */ .dark-mode .shop__contianer { - background-color: #000000; + background-color: #363636; + color: #d8d1d1; +} + +.dark-mode .shop__title { + color: #b2adad; +} + +.dark-mode .shop__subtitle { + color: #252424; +} + +/* Loading Animation */ +.shop__loading { + width: 100%; + height: 60vh; + display: flex; + justify-content: center; + align-items: center; +} + +/* Responsive Adjustments for Shop Container */ +@media (max-width: 1200px) { + .shop__contianer { + gap: 1.75rem; + } +} + +@media (max-width: 992px) { + .shop__contianer { + gap: 1.5rem; + } +} + +@media (max-width: 768px) { + .shop__contianer { + gap: 1.25rem; + padding: 0.5rem 0; + } +} + +@media (max-width: 576px) { + .shop__contianer { + gap: 1rem; + } +} + +/* Smooth Scrolling */ +html { + scroll-behavior: smooth; +} + +/* Global Typography Enhancements */ +body { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizeLegibility; +} + +/* Animation for page load */ +@keyframes fadeIn { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } } diff --git a/client/src/components/Shop/Shop.js b/client/src/components/Shop/Shop.js index c5472304..9e82d07e 100644 --- a/client/src/components/Shop/Shop.js +++ b/client/src/components/Shop/Shop.js @@ -1,38 +1,80 @@ -import { useEffect, useState } from 'react'; -import { TabTitle } from '../../utils/General'; +import { useEffect, useState } from "react"; +import { TabTitle } from "../../utils/General"; import axios from "axios"; -import ShopCategory from './Container/ShopCategory'; -import './Shop.css'; -import ReactLoading from 'react-loading'; +import ShopCategory from "./Container/ShopCategory"; +import "./Shop.css"; +import ReactLoading from "react-loading"; const Shop = () => { - TabTitle("Shop - SHEMA") - const [ menItems, setMenItems ] = useState() - const [ womenItems, setWomenItems ] = useState() - const [ kidsItems, setKidsItems ] = useState() - const [ loading , setLoading ] = useState(true) + TabTitle("Shop - SHEMA"); + const [menItems, setMenItems] = useState([]); + const [womenItems, setWomenItems] = useState([]); + const [kidsItems, setKidsItems] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); - useEffect(() => { - axios.get("https://shema-backend.vercel.app/api/items") - .then(res => { - setMenItems(res.data.filter((item) => item.category === "men")) - setKidsItems(res.data.filter((item) => item.category === "kids" )) - setWomenItems(res.data.filter((item) => item.category === "women")) - setLoading(false) - }) - .catch(err => console.log(err)) - window.scrollTo(0, 0) - - }, []) + useEffect(() => { + const controller = new AbortController(); + setLoading(true); + setError(null); + axios + .get("https://shema-backend.vercel.app/api/items", { signal: controller.signal }) + .then((res) => { + const data = Array.isArray(res.data) ? res.data : []; + const men = data.filter((item) => item?.category === "men"); + const women = data.filter((item) => item?.category === "women"); + const kids = data.filter((item) => item?.category === "kids"); + setMenItems(men); + setWomenItems(women); + setKidsItems(kids); + }) + .catch((err) => { + if (axios.isCancel(err)) return; + console.error(err); + setError("Failed to load products. Please try again."); + }) + .finally(() => setLoading(false)); + window.scrollTo(0, 0); + return () => controller.abort(); + }, []); - return ( -
- {loading && } - {menItems && } - {womenItems && } - {kidsItems && } + return ( +
+ {loading && ( + + )} + {error && ( +
+ {error}
- ); -} - -export default Shop; \ No newline at end of file + )} + {menItems && menItems.length > 0 && ( + + )} + {womenItems && womenItems.length > 0 && ( + + )} + {kidsItems && kidsItems.length > 0 && ( + + )} +
+ ); +}; + +export default Shop;