diff --git a/prisma/initial_data.ts b/prisma/initial_data.ts
index 3ab5380..1c3bcf9 100644
--- a/prisma/initial_data.ts
+++ b/prisma/initial_data.ts
@@ -30,9 +30,9 @@ export const categories = [
];
export const variantAttributes = [
- { name: "no aplica" },
{ name: "talla" },
{ name: "dimensiones" },
+ { name: "no aplica" },
]
export const products = [
@@ -357,74 +357,74 @@ export const products = [
export const variantAttributeValues = [
// --- POLOS (talla: S, M, L) ---
- { attributeId: 1, productId: 1, value: "S", price: 20.0 },
- { attributeId: 1, productId: 1, value: "M", price: 20.0 },
- { attributeId: 1, productId: 1, value: "L", price: 20.0 },
+ { attributeId: 1, productId: 1, value: "Small", price: 20.0 },
+ { attributeId: 1, productId: 1, value: "Medium", price: 20.0 },
+ { attributeId: 1, productId: 1, value: "Large", price: 20.0 },
- { attributeId: 1, productId: 2, value: "S", price: 20.0 },
- { attributeId: 1, productId: 2, value: "M", price: 20.0 },
- { attributeId: 1, productId: 2, value: "L", price: 20.0 },
+ { attributeId: 1, productId: 2, value: "Small", price: 20.0 },
+ { attributeId: 1, productId: 2, value: "Medium", price: 20.0 },
+ { attributeId: 1, productId: 2, value: "Large", price: 20.0 },
- { attributeId: 1, productId: 3, value: "S", price: 20.0 },
- { attributeId: 1, productId: 3, value: "M", price: 20.0 },
- { attributeId: 1, productId: 3, value: "L", price: 20.0 },
+ { attributeId: 1, productId: 3, value: "Small", price: 20.0 },
+ { attributeId: 1, productId: 3, value: "Medium", price: 20.0 },
+ { attributeId: 1, productId: 3, value: "Large", price: 20.0 },
- { attributeId: 1, productId: 4, value: "S", price: 20.0 },
- { attributeId: 1, productId: 4, value: "M", price: 20.0 },
- { attributeId: 1, productId: 4, value: "L", price: 20.0 },
+ { attributeId: 1, productId: 4, value: "Small", price: 20.0 },
+ { attributeId: 1, productId: 4, value: "Medium", price: 20.0 },
+ { attributeId: 1, productId: 4, value: "Large", price: 20.0 },
- { attributeId: 1, productId: 5, value: "S", price: 25.0 },
- { attributeId: 1, productId: 5, value: "M", price: 25.0 },
- { attributeId: 1, productId: 5, value: "L", price: 25.0 },
+ { attributeId: 1, productId: 5, value: "Small", price: 25.0 },
+ { attributeId: 1, productId: 5, value: "Medium", price: 25.0 },
+ { attributeId: 1, productId: 5, value: "Large", price: 25.0 },
- { attributeId: 1, productId: 6, value: "S", price: 25.0 },
- { attributeId: 1, productId: 6, value: "M", price: 25.0 },
- { attributeId: 1, productId: 6, value: "L", price: 25.0 },
+ { attributeId: 1, productId: 6, value: "Small", price: 25.0 },
+ { attributeId: 1, productId: 6, value: "Medium", price: 25.0 },
+ { attributeId: 1, productId: 6, value: "Large", price: 25.0 },
- { attributeId: 1, productId: 7, value: "S", price: 25.0 },
- { attributeId: 1, productId: 7, value: "M", price: 25.0 },
- { attributeId: 1, productId: 7, value: "L", price: 25.0 },
+ { attributeId: 1, productId: 7, value: "Small", price: 25.0 },
+ { attributeId: 1, productId: 7, value: "Medium", price: 25.0 },
+ { attributeId: 1, productId: 7, value: "Large", price: 25.0 },
- { attributeId: 1, productId: 8, value: "S", price: 15.0 },
- { attributeId: 1, productId: 8, value: "M", price: 15.0 },
- { attributeId: 1, productId: 8, value: "L", price: 15.0 },
+ { attributeId: 1, productId: 8, value: "Small", price: 15.0 },
+ { attributeId: 1, productId: 8, value: "Medium", price: 15.0 },
+ { attributeId: 1, productId: 8, value: "Large", price: 15.0 },
- { attributeId: 1, productId: 9, value: "S", price: 15.0 },
- { attributeId: 1, productId: 9, value: "M", price: 15.0 },
- { attributeId: 1, productId: 9, value: "L", price: 15.0 },
+ { attributeId: 1, productId: 9, value: "Small", price: 15.0 },
+ { attributeId: 1, productId: 9, value: "Medium", price: 15.0 },
+ { attributeId: 1, productId: 9, value: "Large", price: 15.0 },
// --- STICKERS (dimensiones: 3x3, 6x6, 9x9) ---
- { attributeId: 2, productId: 10, value: "3x3", price: 2.99 },
- { attributeId: 2, productId: 10, value: "5x5", price: 3.99 },
- { attributeId: 2, productId: 10, value: "10x10", price: 4.99 },
+ { attributeId: 2, productId: 10, value: "3x3 cm", price: 2.99 },
+ { attributeId: 2, productId: 10, value: "5x5 cm", price: 3.99 },
+ { attributeId: 2, productId: 10, value: "10x10 cm", price: 4.99 },
- { attributeId: 2, productId: 11, value: "3x3", price: 2.49 },
- { attributeId: 2, productId: 11, value: "5x5", price: 3.49 },
- { attributeId: 2, productId: 11, value: "10x10", price: 4.49 },
+ { attributeId: 2, productId: 11, value: "3x3 cm", price: 2.49 },
+ { attributeId: 2, productId: 11, value: "5x5 cm", price: 3.49 },
+ { attributeId: 2, productId: 11, value: "10x10 cm", price: 4.49 },
- { attributeId: 2, productId: 12, value: "3x3", price: 3.99 },
- { attributeId: 2, productId: 12, value: "5x5", price: 4.99 },
- { attributeId: 2, productId: 12, value: "10x10", price: 5.99 },
+ { attributeId: 2, productId: 12, value: "3x3 cm", price: 3.99 },
+ { attributeId: 2, productId: 12, value: "5x5 cm", price: 4.99 },
+ { attributeId: 2, productId: 12, value: "10x10 cm", price: 5.99 },
- { attributeId: 2, productId: 13, value: "3x3", price: 2.99 },
- { attributeId: 2, productId: 13, value: "5x5", price: 3.99 },
- { attributeId: 2, productId: 13, value: "10x10", price: 4.99 },
+ { attributeId: 2, productId: 13, value: "3x3 cm", price: 2.99 },
+ { attributeId: 2, productId: 13, value: "5x5 cm", price: 3.99 },
+ { attributeId: 2, productId: 13, value: "10x10 cm", price: 4.99 },
- { attributeId: 2, productId: 14, value: "3x3", price: 2.49 },
- { attributeId: 2, productId: 14, value: "5x5", price: 3.49 },
- { attributeId: 2, productId: 14, value: "10x10", price: 4.49 },
+ { attributeId: 2, productId: 14, value: "3x3 cm", price: 2.49 },
+ { attributeId: 2, productId: 14, value: "5x5 cm", price: 3.49 },
+ { attributeId: 2, productId: 14, value: "10x10 cm", price: 4.49 },
- { attributeId: 2, productId: 15, value: "3x3", price: 2.49 },
- { attributeId: 2, productId: 15, value: "5x5", price: 3.49 },
- { attributeId: 2, productId: 15, value: "10x10", price: 4.49 },
+ { attributeId: 2, productId: 15, value: "3x3 cm", price: 2.49 },
+ { attributeId: 2, productId: 15, value: "5x5 cm", price: 3.49 },
+ { attributeId: 2, productId: 15, value: "10x10 cm", price: 4.49 },
- { attributeId: 2, productId: 16, value: "3x3", price: 2.99 },
- { attributeId: 2, productId: 16, value: "5x5", price: 3.99 },
- { attributeId: 2, productId: 16, value: "10x10", price: 4.99 },
+ { attributeId: 2, productId: 16, value: "3x3 cm", price: 2.99 },
+ { attributeId: 2, productId: 16, value: "5x5 cm", price: 3.99 },
+ { attributeId: 2, productId: 16, value: "10x10 cm", price: 4.99 },
- { attributeId: 2, productId: 17, value: "3x3", price: 2.99 },
- { attributeId: 2, productId: 17, value: "5x5", price: 3.99 },
- { attributeId: 2, productId: 17, value: "10x10", price: .99 },
+ { attributeId: 2, productId: 17, value: "3x3 cm", price: 2.99 },
+ { attributeId: 2, productId: 17, value: "5x5 cm", price: 3.99 },
+ { attributeId: 2, productId: 17, value: "10x10 cm", price: 4.99 },
// --- TAZAS (no aplica: Único) ---
{ attributeId: 3, productId: 18, value: "Único", price: 14.99 },
diff --git a/src/routes/category/components/product-card/index.tsx b/src/routes/category/components/product-card/index.tsx
index 23c402b..e5b5c90 100644
--- a/src/routes/category/components/product-card/index.tsx
+++ b/src/routes/category/components/product-card/index.tsx
@@ -31,18 +31,25 @@ export function ProductCard({ product }: ProductCardProps) {
{product.title}
{product.description}
- {isSticker ? (
-
-
- Desde
-
-
- S/{product.minPrice} - S/{product.maxPrice}
-
-
+ {product.categoryId === 3 ? (
+
+
+ Desde
+
+
+ S/{product.minPrice} - S/{product.maxPrice}
+
+
) : (
-
S/{product.price}
- )}
+
+
+ Precio
+
+
+ S/{product.price}
+
+
+ )}
{product.isOnSale && (
diff --git a/src/routes/product/index.tsx b/src/routes/product/index.tsx
index 545544c..247bbab 100644
--- a/src/routes/product/index.tsx
+++ b/src/routes/product/index.tsx
@@ -1,4 +1,4 @@
-import { useState } from "react";
+import { useState, useEffect } from "react";
import { Form, useNavigation } from "react-router";
import { Button, Container, Separator } from "@/components/ui";
@@ -22,7 +22,10 @@ export default function Product({ loaderData }: Route.ComponentProps) {
const { product } = loaderData;
const navigation = useNavigation();
const cartLoading = navigation.state === "submitting";
- const [selectedSize, setSelectedSize] = useState("Medium");
+
+ // Estados para manejar variantes
+ const [selectedVariant, setSelectedVariant] = useState(null);
+ const [currentPrice, setCurrentPrice] = useState(0);
if (!product) {
return ;
@@ -30,6 +33,46 @@ export default function Product({ loaderData }: Route.ComponentProps) {
const showSizeSelector = product.categoryId === 1 || product.categoryId === 3;
+ // Verificar si el producto tiene variantes
+ const hasVariants = product.variantAttributeValues && product.variantAttributeValues.length > 0;
+
+ // Verificar si debe mostrar selectores (solo polos y stickers)
+ const shouldShowVariants = hasVariants && (product.categoryId === 1 || product.categoryId === 3);
+
+ // Agrupar variantes por atributo (en caso de que un producto tenga múltiples tipos de atributos)
+ const variantGroups = shouldShowVariants
+ ? product.variantAttributeValues.reduce((groups, variant) => {
+ const attributeName = variant.variantAttribute.name;
+ if (!groups[attributeName]) {
+ groups[attributeName] = [];
+ }
+ groups[attributeName].push(variant);
+ return groups;
+ }, {} as Record)
+ : {};
+
+ // Inicializar precio y variante seleccionada
+ useEffect(() => {
+ if (hasVariants) {
+ // Seleccionar la primera variante por defecto
+ const firstVariant = product.variantAttributeValues[0];
+ setSelectedVariant(firstVariant.id);
+ setCurrentPrice(firstVariant.price);
+ } else {
+ // Si no hay variantes, usar el precio base del producto (asumiendo que existe)
+ setCurrentPrice(product.price || 0);
+ }
+ }, [product]);
+
+ // Manejar cambio de variante
+ const handleVariantChange = (variantId: number) => {
+ setSelectedVariant(variantId);
+ const variant = product.variantAttributeValues.find(v => v.id === variantId);
+ if (variant) {
+ setCurrentPrice(variant.price);
+ }
+ };
+
const getAttributeValueId = () => { // AQUI TRAER EL AttributeValueId con el cambio de SEBAS
if (
!product.variantAttributeValues ||
@@ -41,29 +84,6 @@ export default function Product({ loaderData }: Route.ComponentProps) {
return product.variantAttributeValues[0].id;
};
- const getSizeOptions = () => {
- if (product.categoryId === 3) {
- return {
- label: "Dimensiones",
- options: [
- { value: "Small", label: "3x3 cm" },
- { value: "Medium", label: "5x5 cm" },
- { value: "Large", label: "10x10 cm" },
- ],
- };
- } else {
- return {
- label: "Talla",
- options: [
- { value: "Small", label: "Small" },
- { value: "Medium", label: "Medium" },
- { value: "Large", label: "Large" },
- ],
- };
- }
- };
-
- const sizeOptions = getSizeOptions();
return (
<>
diff --git a/src/services/chat-system-prompt.ts b/src/services/chat-system-prompt.ts
index 30401b0..38426db 100644
--- a/src/services/chat-system-prompt.ts
+++ b/src/services/chat-system-prompt.ts
@@ -13,32 +13,70 @@ export function generateSystemPrompt({
products,
userCart,
}: SystemPromptConfig): string {
- const onSaleProducts = products.filter((p) => p.isOnSale);
- const salesSection =
- onSaleProducts.length > 0
- ? `
+
+ // Procesar productos con información de variantes
+ const processedProducts = products.map(product => {
+ const category = categories.find((c) => c.id === product.categoryId);
+
+ // Formatear precio según si tiene variantes o no
+ let priceDisplay = "";
+ if (product.price) {
+ priceDisplay = `S/${product.price}`;
+ } else if (product.minPrice && product.maxPrice) {
+ priceDisplay = `S/${product.minPrice} - S/${product.maxPrice}`;
+ }
+
+ // Formatear variantes según el tipo
+ let variantDisplay = "";
+ if (product.variants && product.variants.length > 0 && product.variantType !== 'único') {
+ switch (product.variantType) {
+ case 'talla':
+ const sizes = product.variants.map(v => v.value).join(", ");
+ variantDisplay = `\n- 👕 Tallas disponibles: ${sizes}`;
+ break;
+ case 'dimensión':
+ const dimensions = product.variants
+ .map(v => `${v.value} (S/${v.price})`)
+ .join(", ");
+ variantDisplay = `\n- 📐 Dimensiones: ${dimensions}`;
+ break;
+ default:
+ const options = product.variants
+ .map(v => `${v.value} (S/${v.price})`)
+ .join(", ");
+ variantDisplay = `\n- ⚙️ Opciones: ${options}`;
+ }
+ }
+
+ return {
+ ...product,
+ categoryTitle: category?.title || "Sin categoría",
+ priceDisplay,
+ variantDisplay
+ };
+ });
+
+ // Procesar productos en oferta
+ const onSaleProducts = processedProducts.filter((p) => p.isOnSale);
+ const salesSection = onSaleProducts.length > 0
+ ? `
## 🔥 PRODUCTOS EN OFERTA ESPECIAL:
${onSaleProducts
- .map(
- (product) => `
-- **${product.title}** - S/${product.price} ⚡ [Ver oferta](/products/${product.id})
-`
- )
+ .map(product => `
+- **${product.title}** - ${product.priceDisplay} ⚡ [Ver oferta](/products/${product.id})`)
.join("")}
`
- : "";
+ : "";
+ // Procesar carrito del usuario
const cartSection = userCart?.items?.length
? `
## 🛒 CARRITO ACTUAL DEL USUARIO:
El usuario tiene actualmente ${userCart.items.length} producto(s) en su carrito:
${userCart.items
- .map(
- (item) => `
+ .map(item => `
- **${item.product.title}** (Cantidad: ${item.quantity}) - S/${item.product.price}
- Link: [Ver producto](/products/${item.product.id})
-`
- )
+ Link: [Ver producto](/products/${item.product.id})`)
.join("")}
**IMPORTANTE**: Usa esta información para hacer recomendaciones inteligentes:
@@ -51,6 +89,25 @@ ${userCart.items
`
: "";
+ // Generar categorías
+ const categoriesSection = categories
+ .map(cat => `
+**${cat.title}** (${cat.slug})
+- Descripción: ${cat.description}
+- Link: [Ver categoría](/category/${cat.slug})`)
+ .join("\n");
+
+ // Generar productos
+ const productsSection = processedProducts
+ .map(product => `
+**${product.title}**
+- 💰 Precio: ${product.priceDisplay}${product.isOnSale ? " ⚡ ¡EN OFERTA!" : ""}
+- 📝 Descripción: ${product.description}
+- 🏷️ Categoría: ${product.categoryTitle}
+- ✨ Características: ${product.features.join(", ")}${product.variantDisplay}
+- 🔗 Link: [Ver producto](/products/${product.id})`)
+ .join("\n");
+
return `
# Asistente Virtual de Full Stock
@@ -69,40 +126,42 @@ Eres un asistente virtual especializado en **Full Stock**, una tienda de product
## PRODUCTOS DISPONIBLES:
### Categorías:
-${categories
- .map(
- (cat) => `
-**${cat.title}** (${cat.slug})
-- Descripción: ${cat.description}
-- Link: [Ver categoría](/category/${cat.slug})
-`
- )
- .join("\n")}
+${categoriesSection}
### Productos:
-${products
- .map((product) => {
- const category = categories.find((c) => c.id === product.categoryId);
- return `
-**${product.title}**
-- 💰 Precio: S/${product.price}${product.isOnSale ? " ⚡ ¡EN OFERTA!" : ""}
-- 📝 Descripción: ${product.description}
-- 🏷️ Categoría: ${category?.title || "Sin categoría"}
-- ✨ Características: ${product.features.join(", ")}
-- 🔗 Link: [Ver producto](/products/${product.id})
-`;
- })
- .join("\n")}
+${productsSection}
${salesSection}
${cartSection}
+## MANEJO DE VARIANTES DE PRODUCTOS:
+**IMPORTANTE**: Cuando un usuario muestre interés en un producto con variantes:
+
+### Para POLOS (Tallas):
+- Si preguntan por un polo, menciona: "¿Qué talla necesitas: Small, Medium o Large?"
+- Ejemplo: "¡El [Polo React](/products/1) está disponible en tallas S, M y L por S/20! ¿Cuál prefieres?"
+
+### Para STICKERS (Dimensiones):
+- Menciona las opciones con precios: "Tenemos 3 tamaños: 3x3cm (S/2.99), 5x5cm (S/3.99) o 10x10cm (S/4.99)"
+- Ejemplo: "¡El [Sticker Docker](/products/10) viene en varios tamaños! ¿Prefieres 3x3cm (S/2.99), 5x5cm (S/3.99) o 10x10cm (S/4.99)?"
+
+### Para PRODUCTOS ÚNICOS (Tazas):
+- Procede normal, no menciones variantes
+- Ejemplo: "¡La [Taza JavaScript](/products/18) por S/14.99 es perfecta para tu café matutino!"
+
+### Reglas Generales:
+- **SIEMPRE pregunta por la variante** cuando el usuario muestre interés en el producto
+- **Incluye precios** solo si varían entre opciones
+- **Sé específico** sobre las opciones disponibles
+- **Facilita la decisión** con recomendaciones si es necesario
+
## INSTRUCCIONES PARA RESPUESTAS:
- **MANTÉN LAS RESPUESTAS BREVES Y DIRECTAS** (máximo 2-3 oraciones)
- Ve directo al punto, sin explicaciones largas
- Cuando recomiendes productos, SIEMPRE incluye el link en formato: [Nombre del Producto](/products/ID)
- Para categorías, usa links como: [Categoría](/category/slug)
+- **AL MENCIONAR PRODUCTOS CON VARIANTES**, pregunta inmediatamente por la opción preferida
- Responde en **Markdown** para dar formato atractivo
- Sé específico sobre precios, características y beneficios
- Si hay productos en oferta, destácalos con emojis y texto llamativo
@@ -123,6 +182,7 @@ ${cartSection}
- **Personalización**: Adapta según el nivel o tecnología mencionada
- **Storytelling**: Usa curiosidades técnicas o historias para conectar emocionalmente con productos
- **Oportunidades educativas**: Si preguntan sobre tecnologías que tienes en productos, educa brevemente y conecta con la venta
+- **Variantes como valor**: Destaca las opciones disponibles como ventaja del producto
## LÓGICA DE RECOMENDACIONES BASADAS EN CARRITO:
**Si el usuario tiene productos en su carrito y pide recomendaciones:**
@@ -144,17 +204,18 @@ Cuando te pregunten sobre tecnologías que tenemos en productos (React, Docker,
4. **Ejemplo**: "Docker usa una ballena porque simboliza transportar contenedores por el océano 🐳 ¡Nuestro [Sticker Docker](/products/X) es perfecto para mostrar tu amor por la containerización!"
## RESPUESTAS A PREGUNTAS COMUNES:
-- **Tallas**: "Nuestros polos vienen en tallas S, M, L, XL. ¿Cuál prefieres?"
+- **Tallas**: "Nuestros polos vienen en tallas S, M, L. ¿Cuál prefieres?"
+
- **Envío**: "Manejamos envío a todo el país. ¿A qué ciudad lo necesitas?"
- **Materiales**: "Usamos algodón 100% de alta calidad para máxima comodidad"
- **Cuidado**: "Para que dure más, lava en agua fría y evita la secadora"
-## EJEMPLOS DE RESPUESTAS CORTAS:
-- "¡Te recomiendo el [Polo React](/products/1) por S/20.00! 🚀 ¿Qué talla necesitas?"
-- "Perfecto para backend: [Polo Backend Developer](/products/3) ⚡ **EN OFERTA** por S/25.00. ¿Te animas?"
-- **Ejemplo de pregunta técnica relacionada**: "¡La ballena de Docker representa la facilidad de transportar aplicaciones! 🐳 Nuestro [Sticker Docker](/products/X) captura perfectamente esa filosofía. ¿Te gusta coleccionar stickers de tecnología?"
-- **Ejemplo con carrito (React)**: "Veo que tienes el Polo React en tu carrito! Para completar tu look frontend, te recomiendo la [Taza React](/products/Y). ¿Te interesa?"
-- **Ejemplo con carrito (Backend)**: "Perfecto, tienes productos backend en tu carrito. El [Sticker Node.js](/products/Z) combinaría genial. ¿Lo agregamos?"
+## EJEMPLOS DE RESPUESTAS CORTAS CON VARIANTES:
+- "¡Te recomiendo el [Polo React](/products/1) por S/20! 🚀 ¿Qué talla necesitas: S, M o L?"
+
+- "La [Taza JavaScript](/products/18) por S/14.99 es perfecta para programar. ¿La agregamos?"
+- **Ejemplo con carrito (React)**: "Veo que tienes el Polo React! Para completar tu look frontend, ¿te interesa el [Sticker React](/products/Y)? Viene en 3 tamaños diferentes."
+- **Ejemplo con carrito (Backend)**: "Perfecto, tienes productos backend. El [Polo Node.js](/products/Z) combinaría genial. ¿Qué talla usas: S, M o L?"
¿En qué puedo ayudarte hoy a encontrar el producto perfecto para ti? 🛒✨
`;
diff --git a/src/services/product.service.ts b/src/services/product.service.ts
index add02b7..c79e857 100644
--- a/src/services/product.service.ts
+++ b/src/services/product.service.ts
@@ -5,22 +5,39 @@ import type { VariantAttributeValue } from "@/models/variant-attribute.model";
import { getCategoryBySlug } from "./category.service";
-const formattedProduct = (product: ProductVariantValue) => {
- const {variantAttributeValues, ...rest} = product
- const prices = variantAttributeValues.map((v: VariantAttributeValue) => Number(v.price))
- const minPrice = Math.min(...prices)
- const maxPrice = Math.max(...prices)
- if (minPrice === maxPrice) {
- return {
- ...rest,
- price: minPrice
- }
- }
- return {
- ...rest,
- minPrice,
- maxPrice
+const formattedProduct = (product: ProductVariantValue) => {
+ const {variantAttributeValues, ...rest} = product
+
+ const prices = variantAttributeValues.map((v: VariantAttributeValue) => Number(v.price))
+ const minPrice = Math.min(...prices)
+ const maxPrice = Math.max(...prices)
+
+ // Agrupar y formatear variantes
+ const variants = variantAttributeValues.map(v => ({
+ id: v.id,
+ attributeId: v.attributeId,
+ value: v.value,
+ price: Number(v.price)
+ }))
+
+ // Determinar tipo de variante basado en attributeId
+ const getVariantType = (attributeId: number) => {
+ switch (attributeId) {
+ case 1: return 'talla'
+ case 2: return 'dimensión'
+ case 3: return 'único'
+ default: return 'variante'
}
+ }
+
+ const variantType = variants.length > 0 ? getVariantType(variants[0].attributeId) : 'único'
+
+ return {
+ ...rest,
+ variants,
+ variantType,
+ ...(minPrice === maxPrice ? { price: minPrice } : { minPrice, maxPrice })
+ }
}
export async function getProductsByCategorySlug(
@@ -41,7 +58,11 @@ export async function getProductById(id: number): Promise {
const product = await prisma.product.findUnique({
where: { id },
include: {
- variantAttributeValues: true
+ variantAttributeValues: {
+ include: {
+ variantAttribute: true
+ }
+ }
}
});