close

DEV Community

Bastien Moriel
Bastien Moriel

Posted on

react shop practice

import { useState, useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import './Marketplace.css'

function Marketplace({ user }) {
const navigate = useNavigate()
const [products, setProducts] = useState([])
const [quantities, setQuantities] = useState({})
const [basket, setBasket] = useState([])
const [message, setMessage] = useState('')

useEffect(() => {
const load = async () => {
const res = await fetch('/api/products')
const data = await res.json()
setProducts(data)
}
load()
}, [])

const changeQty = (id, delta) => {
setQuantities(prev => ({
...prev,
[id]: Math.max(1, (prev[id] || 1) + delta)
}))
}

const addToBasket = (product) => {
if (!user) { navigate('/login'); return }

const qty      = quantities[product.productID] || 1
const existing = basket.find(i => i.productID === product.productID)

if (existing) {
  setBasket(basket.map(i =>
    i.productID === product.productID
      ? { ...i, quantity: i.quantity + qty }
      : i
  ))
} else {
  setBasket([...basket, {
    productID:     product.productID,
    product_name:  product.product_name,
    product_price: product.product_price,
    quantity:      qty
  }])
}

setMessage('Added to basket!')
setTimeout(() => setMessage(''), 2000)
Enter fullscreen mode Exit fullscreen mode

}

const goToCheckout = () => {
if (basket.length === 0) { alert('Your basket is empty'); return }
navigate('/checkout', { state: { basket } })
}

return (


Marketplace

  {message && <p className="success">{message}</p>}

  {basket.length > 0 && (
    <button className="basket-btn" onClick={goToCheckout}>
      Go to Checkout ({basket.length} items)
    </button>
  )}

  <div className="product-grid">
    {products.map(product => (
      <div key={product.productID} className="product-card">
        <div className="product-img" />
        <p className="product-name">{product.product_name}</p>
        <p className="product-price">£{Number(product.product_price).toFixed(2)}</p>
        <p className="product-stock">Stock: {product.product_stock}</p>
        <p className="product-desc">{product.product_description}</p>
        <div className="product-controls">
          <button onClick={() => changeQty(product.productID, -1)}>-</button>
          <span>{quantities[product.productID] || 1}</span>
          <button onClick={() => changeQty(product.productID, +1)}>+</button>
          <button onClick={() => addToBasket(product)}>
            {user ? 'Add to Basket' : 'Login to Order'}
          </button>
        </div>
      </div>
    ))}
  </div>
</div>

)
}

export default Marketplace

.page { padding: 30px; }

.success {
background: #A2C24A;
color: white;
padding: 10px;
border-radius: 6px;
margin-bottom: 15px;
text-align: center;
}

.basket-btn {
background: #144A5C;
color: white;
border: none;
padding: 10px 20px;
border-radius: 6px;
cursor: pointer;
font-family: 'Gluten', cursive;
margin-bottom: 20px;
}

.product-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
}

.product-card {
border: 1px solid #ccc;
border-radius: 8px;
padding: 16px;
}

.product-img {
background: #c8c8c8;
height: 120px;
border-radius: 6px;
margin-bottom: 10px;
}

.product-name { font-weight: 700; margin-bottom: 5px; }
.product-price { color: #A2C24A; font-weight: 700; margin-bottom: 5px; }
.product-stock { font-size: 13px; margin-bottom: 5px; }
.product-desc { font-size: 13px; color: #666; margin-bottom: 10px; }

.product-controls {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}

.product-controls button {
background: #144A5C;
color: white;
border: none;
border-radius: 6px;
padding: 6px 12px;
cursor: pointer;
font-family: 'Gluten', cursive;
}

Top comments (0)