Home page with the product listing for categories map functionality
import Product from "./Product";
import { Row, Col } from "reactstrap";
import { useProducts } from "./useProducts";
import { useNavigate } from "react-router-dom";
const Home = () => {
const { categories, products } = useProducts();
const navigate = useNavigate();
const navigateToProductView = (url) => {
navigate(url);
};
return (
<div>
<div className="home">
<h2 style={{ textAlign: "center" }}>Enjoy our sales!</h2>
{categories.length
? categories.map((category) => {
const hasProducts = products.filter(
(product) =>
product.category?.id === category.id
);
return hasProducts && hasProducts.length ? (
<div key={category.id}>
<h2 className="category-title">{category.name}</h2>
<Row key={category.id} className="category">
{hasProducts.map((product) => (
<Col
sm="12"
md="3"
key={product.id}
onClick={() =>
navigateToProductView(
`/product-details/${product.id}`
)
}
>
<Product product={product} />
</Col>
))}
</Row>
</div>
) : null;
})
: null}
</div>
</div>
);
};
export default Home;
ProductView.js file
import { useProductView } from "./useProductView";
import {
Row,
Col,
Label,
Input,
Button,
CardImg,
CardText,
CardBody,
CardTitle,
FormGroup,
CardSubtitle,
} from "reactstrap";
import ProductReview from "../ProductReview";
import { Rating } from "react-simple-star-rating";
const ProductView = ({ token, addToBasket }) => {
const {
rating,
product,
getImage,
setRating,
description,
selectedColor,
selectedSize,
selectedQuantity,
setSelectedColor,
setSelectedSize,
handleQuantityChange,
setgetLatestProductUpdate,
} = useProductView();
console.log({product});
if (!product || !product.attributes) {
return null;
}
const { id, attributes } = product;
const quantity = Array.from(Array(Number(attributes.quantity)).keys());
return (
<div className="product-details">
<Row>
<Col sm="12" md="6">
<div className="image-wrapper">
<CardImg
left="true"
width="100%"
src={`http://localhost:1337${getImage(selectedColor)}`}
alt=""
/>
</div>
</Col>
<Col sm="12" md="6">
<CardBody>
<CardTitle>{attributes.name}</CardTitle>
<CardText>{attributes.description}</CardText>
<div className="rating">
<Rating
allowFraction
readonly
size={24}
initialValue={rating.stars}
/>
<span>{`${
rating.count > 1
? `${rating.count} ratings`
: `${rating.count} rating`
}`}</span>
</div>
<CardSubtitle>
<strong>Price: £{attributes.price}</strong>
</CardSubtitle>
<CardSubtitle>{attributes.quantity} items Left</CardSubtitle>
<div>
<CardSubtitle>Sizes:</CardSubtitle>
<div className="sizes">
{attributes.sizes.map((size) => (
<span
key={size.name}
className={`${selectedSize === size.name ? "active" : ""}`}
onClick={() => setSelectedSize(size.name)}
>
{size.name}
</span>
))}
</div>
</div>
<div>
<CardSubtitle>Selected colour: {selectedColor}</CardSubtitle>
<div className="colours">
{attributes.colours.map((colour) => (
<span
key={colour.name}
className={`${
selectedColor === colour.name ? "active" : ""
}`}
onClick={() => setSelectedColor(colour.name)}
>
<img
src={`http://localhost:1337${getImage(colour.name)}`}
alt={colour.name}
/>
</span>
))}
</div>
<FormGroup className="quantity">
<Label for="exampleSelect">Selected items</Label>
<Input
value={selectedQuantity}
type="select"
name="quantity"
id="exampleSelect"
onChange={handleQuantityChange}
>
{quantity.map((number) => (
<option key={number}>{number}</option>
))}
</Input>
</FormGroup>
</div>
<Button
color="primary"
onClick={() =>
addToBasket({
...product,
description,
size: selectedSize,
color: selectedColor,
quantity: selectedQuantity,
imageUrl: getImage(selectedColor),
})
}
>
Add to basket
</Button>
</CardBody>
</Col>
</Row>
<ProductReview
token={token}
productId={id}
setRating={setRating}
setgetLatestProductUpdate={setgetLatestProductUpdate}
/>
</div>
);
};
export default ProductView;
To retrieve data from the Strapi server I use a custom hook with getImage function to view a product from the list after the user click the product card.
useProductView.js
import React, { useEffect, useState } from "react";
import { useLocation, useParams } from "react-router-dom";
export const getQuery = (key, search) => {
const querys = search?.replace("?", "")?.split("&");
const query = querys.find((query) => query.includes(key));
const queryValue = query?.replace(`${key}=`, "");
return queryValue;
};
export const useProductView = () => {
const { id: productId } = useParams();
const [rating, setRating] = useState({ stars: null, count: 0 });
const [getLatestProductUpdate, setgetLatestProductUpdate] = useState(false);
const { search } = useLocation();
const [product, setProduct] = useState({});
const [selectedColor, setSelectedColor] = useState("");
const [selectedSize, setSelectedSize] = useState("");
const [selectedQuantity, setSelectedQuantity] = useState(1);
const handleQuantityChange = ({ target: { value } }) => {
setSelectedQuantity(value);
};
const getImage = (colour) => {
const { attributes } = product;
const image = attributes.images.data.find((image) =>
image.attributes.name.includes(colour)
);
return image?.attributes?.url || "";
};
useEffect(() => {
if (product && product.attributes) {
const { attributes } = product;
setSelectedColor(getQuery("color", search) || attributes.colours[0].name);
setSelectedSize(getQuery("size", search) || attributes.sizes[0].name);
}
}, [product, search, setSelectedColor, setSelectedSize]);
useEffect(() => {
const fetchCategories = async () => {
try {
const {
data: { data },
} = await axios.get(
`http://localhost:1337/api/products/${productId}?populate=*`
);
setProduct(data);
setgetLatestProductUpdate(false);
} catch (error) {
console.log({ error });
}
};
if (productId) {
fetchCategories();
}
}, [productId, getLatestProductUpdate]);
return {
rating,
product,
getImage,
setRating,
selectedSize,
selectedColor,
selectedQuantity,
setSelectedColor,
setSelectedSize,
handleQuantityChange,
setgetLatestProductUpdate,
};
};
Can someone show me how to retrieve the data from Strapi when the user click a product from the list they are able to view that product image desc and price from the images below as you can see i am getting the error product not found and the product is setup in the server

