11import { Form , useNavigation } from "react-router" ;
22
33import { Button , Container , Separator } from "@/components/ui" ;
4+ import { cn } from "@/lib/utils" ;
45import { type Product } from "@/models/product.model" ;
56import { getProductById } from "@/services/product.service" ;
67
78import NotFound from "../not-found" ;
89
910import type { Route } from "./+types" ;
11+ import { useEffect , useState } from "react" ;
12+ import { getCategoryWithVariants } from "@/services/category.service" ;
13+
14+ interface CategoryVariant {
15+ id : number ;
16+ value : string ;
17+ label : string ;
18+ }
1019
1120export async function loader ( { params } : Route . LoaderArgs ) {
1221 try {
1322 const product = await getProductById ( parseInt ( params . id ) ) ;
14- return { product } ;
23+ const categoryWithVariants = product . categoryId
24+ ? await getCategoryWithVariants ( product . categoryId )
25+ : null ;
26+ return { product, categoryWithVariants } ;
1527 } catch {
1628 return { } ;
1729 }
1830}
1931
2032export default function Product ( { loaderData } : Route . ComponentProps ) {
21- const { product } = loaderData ;
33+ const { product, categoryWithVariants } = loaderData ;
2234 const navigation = useNavigation ( ) ;
2335 const cartLoading = navigation . state === "submitting" ;
2436
37+ // Estado simple para variantes
38+ const [ variants , setVariants ] = useState < CategoryVariant [ ] > ( [ ] ) ;
39+ const [ selectedVariant , setSelectedVariant ] =
40+ useState < CategoryVariant | null > ( null ) ;
41+
42+ // Cargar variantes si la categoría las tiene
43+ useEffect ( ( ) => {
44+ if (
45+ ! categoryWithVariants ?. hasVariants ||
46+ ! categoryWithVariants . categoryVariants . length
47+ ) {
48+ setVariants ( [ ] ) ;
49+ setSelectedVariant ( null ) ;
50+ return ;
51+ }
52+
53+ const mappedVariants : CategoryVariant [ ] =
54+ categoryWithVariants . categoryVariants . map ( ( variant ) => ( {
55+ id : variant . id ,
56+ value : variant . value ,
57+ label : variant . label ,
58+ } ) ) ;
59+
60+ setVariants ( mappedVariants ) ;
61+ setSelectedVariant ( mappedVariants [ 0 ] || null ) ;
62+ } , [ categoryWithVariants ?. id , categoryWithVariants ?. hasVariants ] ) ;
63+
2564 if ( ! product ) {
2665 return < NotFound /> ;
2766 }
2867
68+ const hasVariants = categoryWithVariants ?. hasVariants && variants . length > 0 ;
69+
70+ // Helper para obtener el label de la variante
71+ const getVariantLabel = ( ) => {
72+ if ( product . categoryId === 1 ) return "Talla" ;
73+ if ( product . categoryId === 3 ) return "Tamaño" ;
74+ return "Opciones" ;
75+ } ;
76+
2977 return (
3078 < >
3179 < section className = "py-12" >
@@ -45,12 +93,55 @@ export default function Product({ loaderData }: Route.ComponentProps) {
4593 < p className = "text-sm leading-5 text-muted-foreground mb-10" >
4694 { product . description }
4795 </ p >
96+
97+ { /* Toggle Button Group para Variantes - Implementación directa */ }
98+ { hasVariants && (
99+ < div className = "mb-6" >
100+ < div className = "space-y-3" >
101+ < label className = "text-sm font-medium text-foreground" >
102+ { getVariantLabel ( ) }
103+ </ label >
104+ < div className = "flex flex-wrap gap-2" >
105+ { variants . map ( ( variant ) => (
106+ < Button
107+ key = { variant . id }
108+ type = "button"
109+ variant = {
110+ selectedVariant ?. id === variant . id
111+ ? "default"
112+ : "outline"
113+ }
114+ size = "default"
115+ onClick = { ( ) => setSelectedVariant ( variant ) }
116+ className = { cn (
117+ "h-10 px-4 transition-all duration-200" ,
118+ selectedVariant ?. id === variant . id
119+ ? "bg-primary text-primary-foreground border-primary"
120+ : "bg-background text-foreground border-border hover:bg-muted"
121+ ) }
122+ >
123+ { variant . label }
124+ </ Button >
125+ ) ) }
126+ </ div >
127+ </ div >
128+ </ div >
129+ ) }
130+
48131 < Form method = "post" action = "/cart/add-item" >
49132 < input
50133 type = "hidden"
51134 name = "redirectTo"
52135 value = { `/products/${ product . id } ` }
53136 />
137+ < input type = "hidden" name = "productId" value = { product . id } />
138+ { selectedVariant && (
139+ < input
140+ type = "hidden"
141+ name = "categoryVariantId"
142+ value = { selectedVariant . id }
143+ />
144+ ) }
54145 < Button
55146 size = "xl"
56147 className = "w-full md:w-80"
0 commit comments