Skip to content

Commit 885eba2

Browse files
authored
Merge pull request #260 from codeableorg/branch-Jeff3
Refactor: To add information about as availability variables on grid …
2 parents 0defd8e + fc592f4 commit 885eba2

File tree

3 files changed

+87
-14
lines changed

3 files changed

+87
-14
lines changed

src/routes/category/components/product-card/index.tsx

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,71 @@
1-
import { Link } from "react-router";
1+
import { Link, useNavigate } from "react-router";
22

33
import type { Product } from "@/models/product.model";
4+
import { Button } from "@/components/ui";
45

56
interface ProductCardProps {
67
product: Product;
8+
categorySlug: string;
79
}
810

9-
export function ProductCard({ product }: ProductCardProps) {
11+
export function ProductCard({ product, categorySlug }: ProductCardProps) {
12+
const navigate = useNavigate();
13+
let variantTitle: string | null = null;
14+
let variants: string[] = [];
15+
let variantParamName: "size" | "measure" | null = null;
16+
17+
if (categorySlug === "polos") {
18+
variantTitle = "Elige la talla";
19+
variants = ["Small", "Medium", "Large"];
20+
variantParamName = "size";
21+
} else if (categorySlug === "stickers") {
22+
variantTitle = "Elige la medida";
23+
variants = ["3*3", "5*5", "10*10"];
24+
variantParamName = "measure";
25+
}
26+
27+
const handleVariantClick = (
28+
e: React.MouseEvent<HTMLButtonElement>,
29+
variant: string
30+
) => {
31+
e.preventDefault();
32+
e.stopPropagation();
33+
if (variantParamName) {
34+
const paramValue =
35+
variantParamName === "size" ? variant.toLowerCase() : variant;
36+
navigate(`/products/${product.id}?${variantParamName}=${paramValue}`);
37+
}
38+
};
39+
1040
return (
1141
<Link
1242
to={`/products/${product.id}`}
1343
className="block"
1444
data-testid="product-item"
1545
>
1646
<div className="relative flex h-full flex-col overflow-hidden rounded-xl border border-separator group">
17-
<div className="aspect-[3/4] bg-muted">
47+
<div className="relative aspect-[3/4] bg-muted">
1848
<img
1949
src={product.imgSrc}
2050
alt={product.title}
2151
loading="lazy"
2252
className="h-full w-full object-contain transition-transform duration-200 group-hover:scale-105"
2353
/>
54+
{variantTitle && (
55+
<div className="absolute bottom-0 left-0 right-0 flex flex-col items-center bg-black/50 p-4 text-white opacity-0 transition-opacity duration-200 group-hover:opacity-100">
56+
<h2 className="mb-4 text-xl font-bold">{variantTitle}</h2>
57+
<div className="flex gap-2">
58+
{variants.map((variant) => (
59+
<Button
60+
key={variant}
61+
onClick={(e) => handleVariantClick(e, variant)}
62+
>
63+
{variant}
64+
</Button>
65+
))}
66+
</div>
67+
</div>
68+
)}
2469
</div>
2570
<div className="flex grow flex-col gap-2 p-4">
2671
<h2 className="text-sm font-medium">{product.title}</h2>

src/routes/category/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ export default function Category({ loaderData }: Route.ComponentProps) {
8282
/>
8383
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 flex-grow">
8484
{products.map((product) => (
85-
<ProductCard product={product} key={product.id} />
85+
<ProductCard
86+
product={product}
87+
key={product.id}
88+
categorySlug={category.slug}
89+
/>
8690
))}
8791
</div>
8892
</div>

src/routes/product/index.tsx

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { useState } from "react";
2-
import { Form, useNavigation } from "react-router";
1+
import { useEffect, useState } from "react";
2+
import { Form, useNavigation, useSearchParams } from "react-router";
33

44
import { VariantSelector } from "@/components/product/VariantSelector";
55
import { Button, Container, Separator } from "@/components/ui";
@@ -22,17 +22,41 @@ export async function loader({ params }: Route.LoaderArgs) {
2222
export default function Product({ loaderData }: Route.ComponentProps) {
2323
const { product } = loaderData;
2424
const navigation = useNavigation();
25+
const [searchParams] = useSearchParams();
2526
const cartLoading = navigation.state === "submitting";
2627

27-
// Si el producto tiene variantes, selecciona la primera por defecto
28-
const [selectedSize, setSelectedSize] = useState(
29-
product?.variants?.[0]?.size ?? ""
30-
);
28+
const getInitialSize = () => {
29+
const isValidSize = (size: string | null) => {
30+
return size === "small" || size === "medium" || size === "large";
31+
};
32+
const sizeFromUrl = searchParams.get("size");
33+
const availableSizes = product?.variants?.map((v) => v.size) || [];
34+
if (isValidSize(sizeFromUrl) && availableSizes.includes(sizeFromUrl)) {
35+
return sizeFromUrl;
36+
}
37+
return product?.variants?.[0]?.size ?? "";
38+
};
3139

32-
// Si el producto tiene variantes de stickers, selecciona la primera por defecto
33-
const [selectedMeasure, setSelectedMeasure] = useState(
34-
product?.stickersVariants?.[0]?.measure ?? ""
35-
);
40+
const getInitialMeasure = () => {
41+
const isValidMeasure = (measure: string | null) => {
42+
return measure === "3*3" || measure === "5*5" || measure === "10*10";
43+
};
44+
const measureFromUrl = searchParams.get("measure");
45+
const availableMeasures =
46+
product?.stickersVariants?.map((v) => v.measure) || [];
47+
if (isValidMeasure(measureFromUrl) && availableMeasures.includes(measureFromUrl)) {
48+
return measureFromUrl;
49+
}
50+
return product?.stickersVariants?.[0]?.measure ?? "";
51+
};
52+
53+
const [selectedSize, setSelectedSize] = useState(getInitialSize);
54+
const [selectedMeasure, setSelectedMeasure] = useState(getInitialMeasure);
55+
56+
useEffect(() => {
57+
setSelectedSize(getInitialSize);
58+
setSelectedMeasure(getInitialMeasure);
59+
}, [searchParams, product?.id]);
3660

3761
if (!product) {
3862
return <NotFound />;

0 commit comments

Comments
 (0)