Skip to content

Commit c945dee

Browse files
fix stretched featured product images (#220)
* fix stretched carousel imgs * rename files * slice products * fetch products * updated attribs * reduce textsize * add categories * update * fix: build errors * fix: type errors --------- Co-authored-by: Sonia Lomo <49971500+sonylomo@users.noreply.github.com> Co-authored-by: sonylomo <sonylomo1@gmail.com>
1 parent 17d8c3a commit c945dee

File tree

7 files changed

+127
-59
lines changed

7 files changed

+127
-59
lines changed

src/components/shop/ProductCard.jsx

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,43 @@ import { addCommaSeparator, categoryColors } from "../../utilities/utils";
88
function ProductCard({ product }) {
99
const { backgroundColor, color } = categoryColors(product.category);
1010

11+
const attributeWithImages = product.attributes.find(
12+
(attribute) => attribute.images.length > 0
13+
);
14+
const image = attributeWithImages
15+
? attributeWithImages.images.map((img) => img.image)[0]
16+
: "";
17+
const totalStock = product.attributes.reduce(
18+
(acc, attribute) => acc + attribute.stock,
19+
0
20+
);
1121
return (
1222
<div className="border rounded-lg p-2.5 pr-1.5 shadow-sm group hover:bg-green-dark/10 bg-white flex flex-col gap-4 ">
1323
<Link
1424
to={`/shop/item/${product.id}`}
1525
className="aspect-h-1 aspect-w-1 w-full bg-gray-200 lg:aspect-none group-hover:opacity-75 lg:h-96"
1626
>
1727
<LazyLoadImage
18-
src={product.image}
19-
alt="Product image"
28+
src={image}
29+
alt={product.name}
2030
className="w-full h-80 object-cover object-center lg:h-full lg:w-full"
2131
/>
2232
</Link>
2333
<Link
2434
to={`/shop/item/${product.id}`}
2535
className="flex justify-between pr-1"
2636
>
27-
<h3 className="text-md uppercase font-bold text-gray-600">
37+
<h3 className="text-md uppercase font-medium text-gray-600">
2838
{product.name}
2939
</h3>
3040
<div className="p-1 rounded-xl bg-green-dark/10">
31-
{product.stock > 0 ? (
41+
{totalStock > 0 ? (
3242
<p className="text-green-dark font-medium text-sm px-1">
33-
<span> {product.stock}</span>
43+
<span> {totalStock}</span>
3444
<span className="ml-2">items left</span>
3545
</p>
3646
) : (
37-
<div className=" text-red-800 p-1 rounded-lg bg-red-800/20 font-bold text-base">
47+
<div className=" text-red-800 p-1 rounded-lg bg-red-800/20 font-bold text-sm">
3848
<p>Out of stock</p>
3949
</div>
4050
)}
@@ -63,14 +73,37 @@ function ProductCard({ product }) {
6373
}
6474
export default ProductCard;
6575

76+
const imagePropTypes = PropTypes.shape({
77+
id: PropTypes.number.isRequired,
78+
product_attribute: PropTypes.number.isRequired,
79+
image: PropTypes.string.isRequired,
80+
is_primary: PropTypes.bool.isRequired,
81+
angle: PropTypes.string.isRequired,
82+
});
83+
84+
const sizePropTypes = PropTypes.shape({
85+
id: PropTypes.number.isRequired,
86+
name: PropTypes.string.isRequired,
87+
});
88+
89+
const attributePropTypes = PropTypes.shape({
90+
id: PropTypes.number.isRequired,
91+
size: PropTypes.arrayOf(sizePropTypes).isRequired,
92+
color: PropTypes.string.isRequired,
93+
stock: PropTypes.number.isRequired,
94+
images: PropTypes.arrayOf(imagePropTypes).isRequired,
95+
});
96+
97+
const ProductCardPropTypes = {
98+
id: PropTypes.number.isRequired,
99+
name: PropTypes.string.isRequired,
100+
slug: PropTypes.string.isRequired,
101+
description: PropTypes.string.isRequired,
102+
price: PropTypes.string.isRequired,
103+
category: PropTypes.string.isRequired,
104+
is_featured: PropTypes.bool.isRequired,
105+
attributes: PropTypes.arrayOf(attributePropTypes).isRequired,
106+
};
66107
ProductCard.propTypes = {
67-
product: PropTypes.shape({
68-
id: PropTypes.number.isRequired,
69-
name: PropTypes.string.isRequired,
70-
description: PropTypes.string,
71-
price: PropTypes.number.isRequired,
72-
image: PropTypes.string,
73-
stock: PropTypes.number.isRequired,
74-
category: PropTypes.string.isRequired,
75-
}).isRequired,
108+
product: PropTypes.shape(ProductCardPropTypes).isRequired,
76109
};

src/hooks/Queries/shop/useSwagList.jsx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
// https://apis.spaceyatech.com/api/swaggs/
21
import { useQuery } from "@tanstack/react-query";
32
import toast from "react-hot-toast";
43
import publicAxios from "../../../api/publicAxios";
54

65
const fetchSwag = async () => {
76
try {
8-
const response = await publicAxios.get("/swaggs/");
9-
7+
const response = await publicAxios.get("/swaggsnew");
108
return response.data;
119
} catch (error) {
1210
toast.error("Error fetching swag list");
@@ -38,4 +36,21 @@ const useSingleSwag = (id) =>
3836
refetchOnWindowFocus: false,
3937
});
4038

41-
export { useSingleSwag, useSwagList };
39+
const fetchSwagCategories = async () => {
40+
try {
41+
const response = await publicAxios.get("/product-categories");
42+
return response.data;
43+
} catch (error) {
44+
toast.error("Error fetching swag list");
45+
throw error;
46+
}
47+
};
48+
49+
const useSwagCategory = () =>
50+
useQuery({
51+
queryKey: ["swagCategory"],
52+
queryFn: () => fetchSwagCategories(),
53+
refetchOnWindowFocus: false,
54+
});
55+
56+
export { useSingleSwag, useSwagList, useSwagCategory };

src/pages/shop/Homepage.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import SeoMetadata from "../../components/SeoMetadata";
22
import CartIcon from "../../components/shop/CartIcon";
33
import Banner from "./sections/Banner/index";
4+
import BrowseProducts from "./sections/BrowseProducts";
45
import FaqSection from "./sections/FaqSection";
5-
import FeaturedProducts from "./sections/FeaturedProducts";
66
import FilterSection from "./sections/FilterSection";
7-
import NewProducts from "./sections/NewProducts";
7+
import NewProducts from "./sections/NewArrivals";
88

99
function Homepage() {
1010
return (
@@ -24,8 +24,8 @@ function Homepage() {
2424
</div>
2525
<Banner />
2626
<FilterSection />
27-
<FeaturedProducts />
2827
<NewProducts />
28+
<BrowseProducts />
2929
<FaqSection />
3030
</div>
3131
</>

src/pages/shop/sections/Banner/Carousal.jsx

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ function Carousel() {
77
const [width, setWidth] = useState(0);
88
const [selectedIndex, setSelectedIndex] = useState(0);
99

10-
const { data: swagList, isSuccess } = useSwagList();
10+
const { data, isSuccess } = useSwagList();
11+
const swagList = Array.isArray(data)
12+
? data.filter((item) => item.is_featured === true)
13+
: [];
14+
1115
const carouselRef = useRef(null);
1216

1317
useEffect(() => {
@@ -48,16 +52,24 @@ function Carousel() {
4852
className="overflow-hidden w-full md:rounded-2xl h-full scrollbar-hide cursor-grab "
4953
>
5054
<div className="flex -ml-2.5 h-full">
51-
{isSuccess &&
52-
swagList?.map(({ image, name, id }) => (
53-
<div key={id} className="relative min-w-full pl-2.5 h-full">
54-
<LazyLoadImage
55-
className="w-full h-full md:rounded-2xl"
56-
src={image}
57-
alt={name}
58-
/>
59-
</div>
60-
))}
55+
{Array.isArray(swagList) &&
56+
swagList.map(({ attributes, name, id }) => {
57+
const attributeWithImages = attributes.find(
58+
(attribute) => attribute.images.length > 0
59+
);
60+
const image = attributeWithImages
61+
? attributeWithImages.images.map((img) => img.image)[0]
62+
: "";
63+
return (
64+
<div key={id} className="relative min-w-full pl-2.5 h-full">
65+
<LazyLoadImage
66+
className="w-full h-full md:rounded-2xl object-cover"
67+
src={image}
68+
alt={name}
69+
/>
70+
</div>
71+
);
72+
})}
6173
</div>
6274
</div>
6375
</div>
@@ -76,15 +88,16 @@ function Carousel() {
7688
Shop Now
7789
</Link>
7890
<div className="flex justify-center bg-black/60 rounded-3xl gap-3 px-2 py-1.5">
79-
{swagList?.map((_, index) => (
80-
<button
81-
key={crypto.randomUUID()}
82-
type="button"
83-
aria-label={`Slide ${index + 1}`}
84-
className={`cursor-pointer relative p-0 outline-none border-0 rounded-full h-[9px] w-[9px] ${index === selectedIndex ? " bg-green-dark" : "bg-white"}`}
85-
onClick={() => scrollToIndex(index)}
86-
/>
87-
))}
91+
{Array.isArray(swagList) &&
92+
swagList.map((_, index) => (
93+
<button
94+
key={crypto.randomUUID()}
95+
type="button"
96+
aria-label={`Slide ${index + 1}`}
97+
className={`cursor-pointer relative p-0 outline-none border-0 rounded-full h-[9px] w-[9px] ${index === selectedIndex ? " bg-green-dark" : "bg-white"}`}
98+
onClick={() => scrollToIndex(index)}
99+
/>
100+
))}
88101
</div>
89102
</div>
90103
</>

src/pages/shop/sections/NewProducts.jsx renamed to src/pages/shop/sections/BrowseProducts.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import ProductCard from "../../../components/shop/ProductCard";
33
import SectionWrapper from "../../../components/shop/SectionWrapper";
44
import { useSwagList } from "../../../hooks/Queries/shop/useSwagList";
55

6-
function NewProducts() {
7-
const { data: swagList, isSuccess } = useSwagList();
6+
function BrowseProducts() {
7+
const { data: swagList } = useSwagList();
88

99
return (
1010
<LandingWrapper title="Browse">
@@ -15,8 +15,8 @@ function NewProducts() {
1515
</h3>
1616
</section>
1717
<div className="mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 lg:gap-8">
18-
{isSuccess &&
19-
swagList?.map((product) => (
18+
{Array.isArray(swagList) &&
19+
swagList.map((product) => (
2020
<ProductCard key={product.id} product={product} />
2121
))}
2222
</div>
@@ -25,4 +25,4 @@ function NewProducts() {
2525
);
2626
}
2727

28-
export default NewProducts;
28+
export default BrowseProducts;

src/pages/shop/sections/FilterSection.jsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Link, useParams } from "react-router-dom";
33
import SearchInput from "../../../components/shop/SearchInput";
44
import SectionWrapper from "../../../components/shop/SectionWrapper";
55
import SortItems from "../../../components/shop/SortItems";
6-
import { categories } from "../data";
6+
import { useSwagCategory } from "../../../hooks/Queries/shop/useSwagList";
77

88
function FilterSection() {
99
return (
@@ -27,22 +27,28 @@ function FilterSection() {
2727
}
2828

2929
function Categories() {
30+
const { data } = useSwagCategory();
3031
return (
3132
<div className="flex gap-4 flex-wrap ">
32-
{categories.map((item) => (
33-
<CategoryItem key={crypto.randomUUID()} name={item.name} />
34-
))}
33+
{Array.isArray(data) &&
34+
data.map((item) => (
35+
<CategoryItem
36+
key={crypto.randomUUID()}
37+
name={item.name}
38+
slug={item.slug}
39+
/>
40+
))}
3541
</div>
3642
);
3743
}
3844

39-
function CategoryItem({ name }) {
45+
function CategoryItem({ name, slug }) {
4046
const params = useParams();
41-
const category = params.category === name;
47+
const category = params.category === slug;
4248

4349
return (
4450
<Link
45-
to={`/shop/category/${name}`}
51+
to={`/shop/category/${slug}`}
4652
className={`rounded-3xl flex items-center border shadow-sm py-2 px-4 ${category ? "bg-green-dark" : " hover:bg-gray-500/20 "}`}
4753
>
4854
<p
@@ -58,4 +64,5 @@ export default FilterSection;
5864

5965
CategoryItem.propTypes = {
6066
name: PropTypes.string.isRequired,
67+
slug: PropTypes.string.isRequired,
6168
};

src/pages/shop/sections/FeaturedProducts.jsx renamed to src/pages/shop/sections/NewArrivals.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import ProductCard from "../../../components/shop/ProductCard";
33
import SectionWrapper from "../../../components/shop/SectionWrapper";
44
import { useSwagList } from "../../../hooks/Queries/shop/useSwagList";
55

6-
function FeaturedProducts() {
7-
const { data: swagList, isSuccess } = useSwagList();
6+
function NewProducts() {
7+
const { data: swagList } = useSwagList();
88

99
return (
1010
<LandingWrapper title="New Arrivals">
@@ -15,8 +15,8 @@ function FeaturedProducts() {
1515
</h3>
1616
</section>
1717
<div className="mt-8 py-4 flex gap-4 overflow-x-scroll h-full w-full hr-scrollbar">
18-
{isSuccess &&
19-
swagList?.map((product) => (
18+
{Array.isArray(swagList) &&
19+
swagList.slice(0, 10).map((product) => (
2020
<div
2121
className="min-w-[100%] sm:min-w-[50%] lg:min-w-[33%] h-full"
2222
key={product.id}
@@ -30,4 +30,4 @@ function FeaturedProducts() {
3030
);
3131
}
3232

33-
export default FeaturedProducts;
33+
export default NewProducts;

0 commit comments

Comments
 (0)