changes: add test data and remove chat

This commit is contained in:
2025-10-23 12:23:35 -06:00
parent 50485d2458
commit 409c3de802
7 changed files with 386 additions and 99 deletions

View File

@@ -10,7 +10,7 @@ import { addToHistory, getHistory } from '@/lib/history-storage';
import ShoeResultsPopup from '@/components/shoe-results-popup'; import ShoeResultsPopup from '@/components/shoe-results-popup';
import HistorySidebar from '@/components/history-sidebar'; import HistorySidebar from '@/components/history-sidebar';
import { skuIdentificationService } from '@/lib/sku-identification'; import { skuIdentificationService } from '@/lib/sku-identification';
import { fetchProduct, getProductImages, getProductPricing } from '@/lib/product-api'; import { fetchProduct, getProductImages, getProductPricing, fetchTestProduct } from '@/lib/product-api';
type CameraStatus = 'loading' | 'active' | 'denied' | 'no_devices'; type CameraStatus = 'loading' | 'active' | 'denied' | 'no_devices';
@@ -265,51 +265,99 @@ function HomePageContent() {
// Limpiar timeout si la petición completó antes // Limpiar timeout si la petición completó antes
clearTimeout(timeoutId); clearTimeout(timeoutId);
console.log('📦 SKU result:', sku); console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.log('📦 RESULTADO FINAL DEL SKU:');
console.log(' SKU retornado:', sku);
console.log(' Tipo:', typeof sku);
console.log(' Es null:', sku === null);
console.log(' Es string vacío:', sku === '');
console.log(' Es falsy:', !sku);
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
if (sku) { if (sku) {
// SKU encontrado - obtener datos reales del producto // SKU encontrado - obtener datos reales del producto
setDetectedSKU(sku); setDetectedSKU(sku);
// Extraer productId del SKU (primeros 6 caracteres)
// Ejemplo: "18047409" → "180474"
const productId = sku.substring(0, 6);
console.log(`📝 Extrayendo productId: ${productId} del SKU: ${sku}`);
// Intentar obtener datos reales del producto
let shoeWithSKU: Shoe; let shoeWithSKU: Shoe;
try {
const product = await fetchProduct(productId);
if (product) { // 🧪 FLUJO ESPECIAL: Detectar si es un producto de prueba
const images = getProductImages(product); if (sku === 'test_product') {
const pricing = getProductPricing(product); console.log('🧪 ========== FLUJO DE PRUEBA ACTIVADO ==========');
console.log('📦 SKU detectado: test_product');
console.log('✅ Cargando producto genérico desde JSON...');
const testProduct = await fetchTestProduct();
if (testProduct) {
const images = getProductImages(testProduct);
const pricing = getProductPricing(testProduct);
shoeWithSKU = { shoeWithSKU = {
id: Date.now().toString(), id: Date.now().toString(),
name: product.productName, name: testProduct.productName,
brand: product.brand, brand: testProduct.brand,
price: pricing.isAvailable ? pricing.price.toString() : 'No disponible', price: pricing.isAvailable ? pricing.price.toString() : 'No disponible',
image: images[0] || '/placeholder.jpg', image: images[0] || '/placeholder.jpg',
sku: sku, sku: sku,
timestamp: new Date().toISOString() timestamp: new Date().toISOString()
}; };
console.log('✅ Datos del producto obtenidos exitosamente');
console.log('🧪 Producto de prueba cargado exitosamente');
} else { } else {
throw new Error('Product not found'); console.error('❌ Error al cargar producto de prueba, usando fallback');
shoeWithSKU = {
id: Date.now().toString(),
name: 'Producto de Prueba (Error)',
brand: 'Test',
price: 'No disponible',
image: '/placeholder.jpg',
sku: sku,
timestamp: new Date().toISOString()
};
}
console.log('=========================================\n');
} else {
// FLUJO NORMAL: Extraer productId y obtener datos reales
// Extraer productId del SKU (primeros 6 caracteres)
// Ejemplo: "18047409" → "180474"
const productId = sku.substring(0, 6);
console.log(`📝 Extrayendo productId: ${productId} del SKU: ${sku}`);
// Intentar obtener datos reales del producto
try {
const product = await fetchProduct(productId);
if (product) {
const images = getProductImages(product);
const pricing = getProductPricing(product);
shoeWithSKU = {
id: Date.now().toString(),
name: product.productName,
brand: product.brand,
price: pricing.isAvailable ? pricing.price.toString() : 'No disponible',
image: images[0] || '/placeholder.jpg',
sku: sku,
timestamp: new Date().toISOString()
};
console.log('✅ Datos del producto obtenidos exitosamente');
} else {
throw new Error('Product not found');
}
} catch (error) {
console.warn('⚠️ No se pudieron obtener datos del producto, usando fallback:', error);
// Fallback si falla el fetch
shoeWithSKU = {
id: Date.now().toString(),
name: `Producto ${sku}`,
brand: 'Identificado por IA',
price: 'Precio por consultar',
image: '/placeholder.jpg',
sku: sku,
timestamp: new Date().toISOString()
};
} }
} catch (error) {
console.warn('⚠️ No se pudieron obtener datos del producto, usando fallback:', error);
// Fallback si falla el fetch
shoeWithSKU = {
id: Date.now().toString(),
name: `Producto ${sku}`,
brand: 'Identificado por IA',
price: 'Precio por consultar',
image: '/placeholder.jpg',
sku: sku,
timestamp: new Date().toISOString()
};
} }
const updatedHistory = addToHistory(shoeWithSKU); const updatedHistory = addToHistory(shoeWithSKU);

View File

@@ -10,7 +10,7 @@ import { Badge } from "@/components/ui/badge";
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { ExternalLink, Package, Truck, Shield, Star, ChevronRight, Store, Tag, MessageCircle, Sparkles } from 'lucide-react'; import { ExternalLink, Package, Truck, Shield, Star, ChevronRight, Store, Tag, MessageCircle, Sparkles } from 'lucide-react';
import { fetchProduct, getProductImages, getProductPricing, getProductVariants, getProductCategories, getProductClusters, getStockStatus, getProductGender, getProductSeason, getProductOccasion, getProductColors, getProductHighlight, type Product } from '@/lib/product-api'; import { fetchProduct, getProductImages, getProductPricing, getProductVariants, getProductCategories, getProductClusters, getStockStatus, getProductGender, getProductSeason, getProductOccasion, getProductColors, getProductHighlight, fetchTestProduct, type Product } from '@/lib/product-api';
import ChatPromptBubble from '@/components/chat-prompt-bubble'; import ChatPromptBubble from '@/components/chat-prompt-bubble';
interface ShoeResultsPopupProps { interface ShoeResultsPopupProps {
@@ -45,77 +45,107 @@ export default function ShoeResultsPopup({ isOpen, onOpenChange, detectedSKU }:
useEffect(() => { useEffect(() => {
if (isOpen && !product) { if (isOpen && !product) {
setLoading(true); setLoading(true);
// Extract productId from detectedSKU (first 6 characters)
// Example: "18047409" → "180474"
const productId = detectedSKU?.substring(0, 6);
console.log('🔍 ShoeResultsPopup: Buscando producto con SKU:', detectedSKU); console.log('🔍 ShoeResultsPopup: Buscando producto con SKU:', detectedSKU);
console.log('📦 ProductId extraído:', productId);
fetchProduct(productId).then((data) => { // 🧪 FLUJO ESPECIAL: Si es test_product, usar producto genérico
if (data) { if (detectedSKU === 'test_product') {
setProduct(data); console.log('🧪 Producto de prueba detectado en popup');
const images = getProductImages(data);
if (images.length > 0) { fetchTestProduct().then((testProduct) => {
// setActiveImageUrl(images[0]); if (testProduct) {
} setProduct(testProduct);
// Set first available variant
const variants = getProductVariants(data); const images = getProductImages(testProduct);
if (variants.length > 0) { if (images.length > 0) {
setSelectedVariant(variants[0].itemId); // setActiveImageUrl(images[0]);
if (variants[0].sizes.length > 0) { }
setSelectedSize(variants[0].sizes[0]);
// Set first available variant
const variants = getProductVariants(testProduct);
if (variants.length > 0) {
setSelectedVariant(variants[0].itemId);
if (variants[0].sizes.length > 0) {
setSelectedSize(variants[0].sizes[0]);
}
} }
} }
} setLoading(false);
setLoading(false); }).catch((error) => {
}); console.error('Error loading test product:', error);
setLoading(false);
});
} else {
// FLUJO NORMAL: Extract productId from detectedSKU (first 6 characters)
// Example: "18047409" → "180474"
const productId = detectedSKU?.substring(0, 6);
console.log('📦 ProductId extraído:', productId);
fetchProduct(productId).then((data) => {
if (data) {
setProduct(data);
const images = getProductImages(data);
if (images.length > 0) {
// setActiveImageUrl(images[0]);
}
// Set first available variant
const variants = getProductVariants(data);
if (variants.length > 0) {
setSelectedVariant(variants[0].itemId);
if (variants[0].sizes.length > 0) {
setSelectedSize(variants[0].sizes[0]);
}
}
}
setLoading(false);
});
}
} }
}, [isOpen, product, detectedSKU]); }, [isOpen, product, detectedSKU]);
// Show chat prompt when popup opens (contextual message) // Show chat prompt when popup opens (contextual message) - DISABLED
useEffect(() => { // useEffect(() => {
if (isOpen && product) { // if (isOpen && product) {
// Wait 2 seconds after popup opens to show prompt // // Wait 2 seconds after popup opens to show prompt
const timer = setTimeout(() => { // const timer = setTimeout(() => {
const now = Date.now(); // const now = Date.now();
// Only show if we haven't shown a prompt in the last 10 seconds // // Only show if we haven't shown a prompt in the last 10 seconds
if (now - lastPromptTime > 10000) { // if (now - lastPromptTime > 10000) {
setPromptMessage('🤖 ¿Dudas sobre este modelo? Nuestra IA está lista para ayudarte'); // setPromptMessage('🤖 ¿Dudas sobre este modelo? Nuestra IA está lista para ayudarte');
setShowChatPrompt(true); // setShowChatPrompt(true);
setLastPromptTime(now); // setLastPromptTime(now);
} // }
}, 2000); // }, 2000);
return () => clearTimeout(timer); // return () => clearTimeout(timer);
} // }
}, [isOpen, product, lastPromptTime]); // }, [isOpen, product, lastPromptTime]);
// Timer de 15 segundos para mostrar prompts periódicos // Timer de 15 segundos para mostrar prompts periódicos - DISABLED
useEffect(() => { // useEffect(() => {
if (!isOpen) return; // if (!isOpen) return;
const interval = setInterval(() => { // const interval = setInterval(() => {
const now = Date.now(); // const now = Date.now();
// Check if Chatwoot is not already open and enough time has passed // // Check if Chatwoot is not already open and enough time has passed
if (typeof window !== 'undefined' && window.$chatwoot) { // if (typeof window !== 'undefined' && window.$chatwoot) {
// Only show if chat is not open and enough time since last prompt // // Only show if chat is not open and enough time since last prompt
if (now - lastPromptTime > 15000) { // if (now - lastPromptTime > 15000) {
const messages = [ // const messages = [
'👋 ¿Necesitas ayuda para encontrar tu talla perfecta?', // '👋 ¿Necesitas ayuda para encontrar tu talla perfecta?',
'🎯 ¿Buscas algo en específico? Chatea con nuestra IA', // '🎯 ¿Buscas algo en específico? Chatea con nuestra IA',
'💬 Pregúntame sobre tallas, disponibilidad o características', // '💬 Pregúntame sobre tallas, disponibilidad o características',
]; // ];
const randomMessage = messages[Math.floor(Math.random() * messages.length)]; // const randomMessage = messages[Math.floor(Math.random() * messages.length)];
setPromptMessage(randomMessage); // setPromptMessage(randomMessage);
setShowChatPrompt(true); // setShowChatPrompt(true);
setLastPromptTime(now); // setLastPromptTime(now);
} // }
} // }
}, 15000); // Every 15 seconds // }, 15000); // Every 15 seconds
return () => clearInterval(interval); // return () => clearInterval(interval);
}, [isOpen, lastPromptTime]); // }, [isOpen, lastPromptTime]);
// Listen to Chatwoot events to manage popup visibility // Listen to Chatwoot events to manage popup visibility
useEffect(() => { useEffect(() => {
@@ -555,13 +585,13 @@ export default function ShoeResultsPopup({ isOpen, onOpenChange, detectedSKU }:
`}</style> `}</style>
</Drawer.Content> </Drawer.Content>
{/* Chat Prompt Bubble */} {/* Chat Prompt Bubble - DISABLED */}
<ChatPromptBubble {/* <ChatPromptBubble
message={promptMessage} message={promptMessage}
isVisible={showChatPrompt} isVisible={showChatPrompt}
onClose={() => setShowChatPrompt(false)} onClose={() => setShowChatPrompt(false)}
onChatClick={handleOpenChat} onChatClick={handleOpenChat}
/> /> */}
</Drawer.Portal> </Drawer.Portal>
</Drawer.Root> </Drawer.Root>
); );

View File

@@ -321,7 +321,7 @@ export function getProductHighlight(product: Product) {
if (!product.clusterHighlights || Object.keys(product.clusterHighlights).length === 0) { if (!product.clusterHighlights || Object.keys(product.clusterHighlights).length === 0) {
return null; return null;
} }
// Show the highlight from clusterHighlights // Show the highlight from clusterHighlights
const highlight = Object.values(product.clusterHighlights)[0]; const highlight = Object.values(product.clusterHighlights)[0];
return { return {
@@ -330,4 +330,29 @@ export function getProductHighlight(product: Product) {
icon: '⭐', icon: '⭐',
type: 'promotion' type: 'promotion'
}; };
}
/**
* Loads test product data from JSON file
* Used when SKU detection returns "test_product"
*
* The test product data is stored in /public/test-product.json
* and can be edited manually without changing code
*/
export async function fetchTestProduct(): Promise<Product | null> {
try {
const response = await fetch('/test-product.json');
if (!response.ok) {
console.error('Failed to load test product JSON:', response.status);
return null;
}
const testProduct: Product = await response.json();
console.log('✅ Test product loaded from JSON successfully');
return testProduct;
} catch (error) {
console.error('Error loading test product:', error);
return null;
}
} }

View File

@@ -142,15 +142,23 @@ export class SKUIdentificationService {
} }
console.log('✓ Respuesta recibida - Status:', response.status); console.log('✓ Respuesta recibida - Status:', response.status);
console.log('✓ Headers:', Object.fromEntries(response.headers.entries()));
// Try to get response as text first // Try to get response as text first
const responseText = await response.text(); const responseText = await response.text();
console.log('📄 RESPUESTA RAW del servidor Python:');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.log(responseText);
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
// Try to parse as JSON // Try to parse as JSON
let data: any; let data: any;
try { try {
data = JSON.parse(responseText); data = JSON.parse(responseText);
console.log('✓ Respuesta parseada:', data); console.log('✓ Respuesta parseada como JSON:');
console.log(' - status:', data.status, '(tipo:', typeof data.status, ')');
console.log(' - SKU:', data.SKU, '(tipo:', typeof data.SKU, ')');
console.log(' - Objeto completo:', JSON.stringify(data, null, 2));
} catch (parseError) { } catch (parseError) {
console.error('❌ Error al parsear JSON:', parseError); console.error('❌ Error al parsear JSON:', parseError);
console.error(' Respuesta recibida:', responseText); console.error(' Respuesta recibida:', responseText);
@@ -158,25 +166,41 @@ export class SKUIdentificationService {
} }
// Validate response format // Validate response format
console.log('🔍 Validando formato de respuesta...');
if (!this.validateResponse(data)) { if (!this.validateResponse(data)) {
console.error('❌ Validación de formato falló');
throw new Error('Response format validation failed'); throw new Error('Response format validation failed');
} }
console.log('✓ Formato de respuesta válido');
// ONLY return SKU if status is EXACTLY true (not false, not null, not undefined) // ONLY return SKU if status is EXACTLY true (not false, not null, not undefined)
console.log('🔍 Evaluando condiciones para detectar zapato:');
console.log(' - ¿data.status === true?', data.status === true);
console.log(' - ¿data.SKU existe?', !!data.SKU);
console.log(' - ¿data.SKU es string?', typeof data.SKU === 'string');
console.log(' - Valor de data.status:', data.status);
console.log(' - Valor de data.SKU:', data.SKU);
if (data.status === true && data.SKU) { if (data.status === true && data.SKU) {
console.log('✅ ZAPATO ENCONTRADO - SKU:', data.SKU); console.log('✅✅✅ ZAPATO ENCONTRADO ✅✅✅');
console.log('📦 SKU DETECTADO:', data.SKU);
console.log('=========================================\n'); console.log('=========================================\n');
return data.SKU; return data.SKU;
} else { } else {
console.log('❌❌❌ ZAPATO NO ENCONTRADO ❌❌❌');
// Log detailed reason for not finding shoe // Log detailed reason for not finding shoe
if (data.status === false) { if (data.status === false) {
console.log('❌ ZAPATO NO ENCONTRADO - El servidor reportó status: false'); console.log('💡 RAZÓN: El servidor reportó status: false');
} else if (data.status === null) { } else if (data.status === null) {
console.log('❌ ZAPATO NO ENCONTRADO - El servidor reportó status: null'); console.log('💡 RAZÓN: El servidor reportó status: null');
} else if (data.status !== true) {
console.log('💡 RAZÓN: status no es exactamente true, es:', data.status, 'tipo:', typeof data.status);
} else if (!data.SKU) { } else if (!data.SKU) {
console.log('❌ ZAPATO NO ENCONTRADO - status: true pero SKU es null/vacío'); console.log('💡 RAZÓN: status es true pero SKU es null/vacío/undefined');
console.log(' SKU value:', data.SKU);
console.log(' SKU type:', typeof data.SKU);
} else { } else {
console.log('❌ ZAPATO NO ENCONTRADO - status:', data.status, 'SKU:', data.SKU); console.log('💡 RAZÓN: Condición desconocida - status:', data.status, 'SKU:', data.SKU);
} }
console.log('=========================================\n'); console.log('=========================================\n');
return null; return null;

View File

@@ -17,6 +17,18 @@ const nextConfig: NextConfig = {
protocol: 'https', protocol: 'https',
hostname: 'b2cimpulsmx.vteximg.com.br', hostname: 'b2cimpulsmx.vteximg.com.br',
}, },
{
protocol: 'https',
hostname: 'via.placeholder.com',
},
{
protocol: 'https',
hostname: 'iili.io',
},
{
protocol: 'https',
hostname: 'm.media-amazon.com',
},
], ],
}, },
}; };

View File

@@ -173,6 +173,154 @@
"Color": ["Blanco"], "Color": ["Blanco"],
"Género": ["Unisex"], "Género": ["Unisex"],
"Ocasión": ["Casual"] "Ocasión": ["Casual"]
},
{
"itemId": "TEST001-003",
"name": "Zapato de Prueba - Talla 27",
"nameComplete": "Zapato de Prueba - Modelo Demo - Talla 27",
"complementName": "Negro/Blanco",
"ean": "0000000000002",
"referenceId": [{ "Key": "RefId", "Value": "TEST001" }],
"measurementUnit": "un",
"unitMultiplier": 1,
"modalType": null,
"isKit": false,
"images": [
{
"imageId": "test-img-1",
"imageLabel": "Principal",
"imageTag": "main",
"imageUrl": "https://m.media-amazon.com/images/I/71cNckyVJ0L._AC_SX695_.jpg",
"imageText": "Zapato de Prueba",
"imageLastModified": "2024-01-01T00:00:00.000Z"
},
{
"imageId": "test-img-2",
"imageLabel": "Principal",
"imageTag": "main",
"imageUrl": "https://m.media-amazon.com/images/I/71uoxNkz6JL._AC_SX695_.jpg",
"imageText": "Zapato de Prueba",
"imageLastModified": "2024-01-01T00:00:00.000Z"
},
{
"imageId": "test-img-3",
"imageLabel": "Principal",
"imageTag": "main",
"imageUrl": "https://m.media-amazon.com/images/I/71DkrehA2WL._AC_SX695_.jpg",
"imageText": "Zapato de Prueba",
"imageLastModified": "2024-01-01T00:00:00.000Z"
}
],
"Talla": ["27"],
"variations": [],
"sellers": [
{
"sellerId": "test-seller",
"sellerName": "Test Seller",
"addToCartLink": "",
"sellerDefault": true,
"commertialOffer": {
"Price": 999.99,
"ListPrice": 1299.99,
"PriceWithoutDiscount": 1299.99,
"FullSellingPrice": 999.99,
"RewardValue": 0,
"PriceValidUntil": "2025-12-31T23:59:59.000Z",
"AvailableQuantity": 3,
"IsAvailable": true,
"GiftSkuIds": [],
"Installments": [
{
"Value": 999.99,
"InterestRate": 0,
"TotalValuePlusInterestRate": 999.99,
"NumberOfInstallments": 1
}
],
"discountHighLight": [],
"teasers": []
}
}
],
"Videos": [],
"estimatedDateArrival": null,
"Color": ["Blanco"],
"Género": ["Unisex"],
"Ocasión": ["Casual"]
},
{
"itemId": "TEST001-004",
"name": "Zapato de Prueba - Talla 28",
"nameComplete": "Zapato de Prueba - Modelo Demo - Talla 28",
"complementName": "Negro/Blanco",
"ean": "0000000000003",
"referenceId": [{ "Key": "RefId", "Value": "TEST001" }],
"measurementUnit": "un",
"unitMultiplier": 1,
"modalType": null,
"isKit": false,
"images": [
{
"imageId": "test-img-1",
"imageLabel": "Principal",
"imageTag": "main",
"imageUrl": "https://m.media-amazon.com/images/I/71cNckyVJ0L._AC_SX695_.jpg",
"imageText": "Zapato de Prueba",
"imageLastModified": "2024-01-01T00:00:00.000Z"
},
{
"imageId": "test-img-2",
"imageLabel": "Principal",
"imageTag": "main",
"imageUrl": "https://m.media-amazon.com/images/I/71uoxNkz6JL._AC_SX695_.jpg",
"imageText": "Zapato de Prueba",
"imageLastModified": "2024-01-01T00:00:00.000Z"
},
{
"imageId": "test-img-3",
"imageLabel": "Principal",
"imageTag": "main",
"imageUrl": "https://m.media-amazon.com/images/I/71DkrehA2WL._AC_SX695_.jpg",
"imageText": "Zapato de Prueba",
"imageLastModified": "2024-01-01T00:00:00.000Z"
}
],
"Talla": ["28"],
"variations": [],
"sellers": [
{
"sellerId": "test-seller",
"sellerName": "Test Seller",
"addToCartLink": "",
"sellerDefault": true,
"commertialOffer": {
"Price": 999.99,
"ListPrice": 1299.99,
"PriceWithoutDiscount": 1299.99,
"FullSellingPrice": 999.99,
"RewardValue": 0,
"PriceValidUntil": "2025-12-31T23:59:59.000Z",
"AvailableQuantity": 3,
"IsAvailable": true,
"GiftSkuIds": [],
"Installments": [
{
"Value": 999.99,
"InterestRate": 0,
"TotalValuePlusInterestRate": 999.99,
"NumberOfInstallments": 1
}
],
"discountHighLight": [],
"teasers": []
}
}
],
"Videos": [],
"estimatedDateArrival": null,
"Color": ["Blanco"],
"Género": ["Unisex"],
"Ocasión": ["Casual"]
} }
] ]
} }