Skip to main content

Overview

The ProductCard component is a presentational component that displays individual menu items in a visually appealing card format. It shows the product image, name, price, an optional badge, and an ingredients button.

Location

src/components/ProductCard/ProductCard.jsx
src/components/ProductCard/ProductCard.css

Props

title
string
required
The name of the menu item to display.
title="Hamburguesa Clásica"
price
number
required
The price of the item. Displayed with a dollar sign prefix.
price={12.99}
image
string
required
URL or path to the product image.
image="https://example.com/burger.jpg"
badge
string
Optional badge text to display in the top-right corner of the card. Useful for labels like “NEW”, “POPULAR”, “SPICY”, etc.
badge="Nuevo"
If not provided or null, no badge is displayed.

Source Code

src/components/ProductCard/ProductCard.jsx
import "./ProductCard.css";

export default function ProductCard({ title, price, image, badge }) {
  return (
    <div className="product-card">

      {badge && <div className="badge">{badge}</div>}

      <img src={image} alt={title} />

      <div className="product-info">
        <h4>{title}</h4>
        <span>${price}</span>
      </div>

      <button className="product-btn">Ingredientes</button>
    </div>
  );
}

Usage Example

Basic Usage

import ProductCard from "./components/ProductCard/ProductCard";

function MenuGrid() {
  return (
    <div className="products-grid">
      <ProductCard
        title="Hamburguesa Clásica"
        price={12.99}
        image="/images/burger.jpg"
      />
    </div>
  );
}

With Badge

<ProductCard
  title="Hamburguesa Deluxe"
  price={15.99}
  image="/images/deluxe-burger.jpg"
  badge="Popular"
/>

From API Data

In the actual application, ProductCard is rendered from API data:
src/pages/Menu.jsx
import { useState, useEffect } from "react";
import ProductCard from "../components/ProductCard/ProductCard";
import { getProductsByCategory } from "../services/api";

export default function Menu() {
  const [products, setProducts] = useState([]);
  const [activeCategoryId, setActiveCategoryId] = useState(null);
  
  useEffect(() => {
    if (activeCategoryId === null) return;
    
    getProductsByCategory(activeCategoryId)
      .then((data) => setProducts(data))
      .catch((err) => console.error(err));
  }, [activeCategoryId]);
  
  return (
    <section className="products-grid">
      {products.map((product) => (
        <ProductCard
          key={product.id}
          title={product.name}
          price={product.price}
          image={product.imageUrl}
          badge={product.badge ?? null}
        />
      ))}
    </section>
  );
}

Structure

The component consists of four main sections:

1. Badge (Conditional)

{badge && <div className="badge">{badge}</div>}
Only rendered when the badge prop is provided. Positioned absolutely in the top-right corner of the card.

2. Product Image

<img src={image} alt={title} />
Displays the product image with the product title as alt text for accessibility.

3. Product Info Section

<div className="product-info">
  <h4>{title}</h4>
  <span>${price}</span>
</div>
Contains the product name and price. The price is automatically prefixed with a dollar sign.

4. Ingredients Button

<button className="product-btn">Ingredientes</button>
Currently, the “Ingredientes” button is static and doesn’t have an onClick handler. This could be extended to show a modal or expand the card to display ingredients.

Styling Details

The ProductCard uses CSS classes for styling:
  • .product-card - Main container with card styling, shadows, and borders
  • .badge - Absolute positioned badge in top-right corner
  • .product-info - Flex container for title and price
  • .product-btn - Styled button at the bottom of the card

Badge Functionality

The badge feature allows you to highlight special products:
<ProductCard
  title="Spicy Burger"
  price={13.99}
  image="/spicy.jpg"
  badge="Picante 🌶️"
/>
A small label appears in the top-right corner of the card.

Common Badge Values

Based on the API integration, common badge values might include:
  • "Nuevo" - New menu items
  • "Popular" - Best-selling items
  • "Picante" - Spicy dishes
  • "Vegetariano" - Vegetarian options
  • "Especial" - Daily specials

Accessibility

The component includes basic accessibility features:
<img src={image} alt={title} />
The image uses the product title as alt text, ensuring screen readers can describe the product to visually impaired users.
The ingredients button currently has no functionality. When implementing the onClick handler, ensure it’s keyboard accessible and has proper ARIA attributes if it triggers a modal.

Layout in Grid

ProductCards are typically displayed in a responsive grid:
.products-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 2rem;
}
This creates a responsive layout that adapts to different screen sizes.

Extending the Component

Potential enhancements:

Ingredients Modal

Add an onClick handler to the button that opens a modal showing ingredients and nutritional information.

Add to Cart

Add functionality to add the product to a shopping cart.

Customization

Allow users to customize toppings or options before adding to cart.

Ratings

Display customer ratings and reviews.

Props Validation

For production use, consider adding PropTypes:
import PropTypes from 'prop-types';

ProductCard.propTypes = {
  title: PropTypes.string.isRequired,
  price: PropTypes.number.isRequired,
  image: PropTypes.string.isRequired,
  badge: PropTypes.string
};

Build docs developers (and LLMs) love