From 3666f4dee850ec40ea5fa872d42d6a5e4aca51e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoni=20Nu=C3=B1ez=20Romeu?= Date: Thu, 16 Jul 2026 15:58:35 +0200 Subject: [PATCH] fix: update ProductResults and admin panel for parapharmacy - Updated ProductResults component with new source labels - Added price display for parapharmacy products - Updated admin panel to search both CIMA and Parapharmacy - Updated getSourceBadge to handle parapharmacy sources - Added CSS for product price display --- .../src/components/ProductResults.css | 6 ++ .../src/components/ProductResults.jsx | 21 ++++- .../components/admin/PharmacyProductLink.jsx | 94 +++++++++++++------ 3 files changed, 87 insertions(+), 34 deletions(-) diff --git a/apps/frontend/src/components/ProductResults.css b/apps/frontend/src/components/ProductResults.css index fb17ac6..fdb2a84 100644 --- a/apps/frontend/src/components/ProductResults.css +++ b/apps/frontend/src/components/ProductResults.css @@ -130,6 +130,12 @@ font-weight: 600; } +.product-price { + color: var(--primary); + font-weight: 700; + font-size: 1.1rem; +} + .product-card-footer { padding-top: 0.75rem; border-top: 1px solid var(--outline-variant); diff --git a/apps/frontend/src/components/ProductResults.jsx b/apps/frontend/src/components/ProductResults.jsx index db9c680..c7973d1 100644 --- a/apps/frontend/src/components/ProductResults.jsx +++ b/apps/frontend/src/components/ProductResults.jsx @@ -3,19 +3,27 @@ import './ProductResults.css'; const categoryLabels = { otc: 'Sin Receta', - baby_food: 'Alimentación Infantil', - baby_milk: 'Leche de Fórmula', - baby_cereal: 'Cereales Bebé' + parapharmacy: 'Parafarmacia', + dermocosmética: 'Dermocosmética', + 'Fórmulas lácteas': 'Fórmulas lácteas', + vitaminas: 'Vitaminas', + analgésicos: 'Analgésicos' }; const sourceColors = { cima: '#2563eb', - openfoodfacts: '#16a34a' + promofarma: '#16a34a', + docmorris: '#e11d48', + primor: '#7c3aed', + parapharmacy: '#16a34a' }; const sourceLabels = { cima: 'CIMA', - openfoodfacts: 'Open Food Facts' + promofarma: 'Promofarma', + docmorris: 'DocMorris', + primor: 'Primor', + parapharmacy: 'Parafarmacia' }; function ProductResults({ products, onSelect }) { @@ -95,6 +103,9 @@ function ProductCard({ product, onSelect }) { {product.brand && (

Marca: {product.brand}

)} + {product.price != null && ( +

Precio: {product.price} €

+ )} {product.source === 'cima' && product.active_ingredient && (

Principio Activo: {product.active_ingredient}

)} diff --git a/apps/frontend/src/components/admin/PharmacyProductLink.jsx b/apps/frontend/src/components/admin/PharmacyProductLink.jsx index dad7ac0..fe6ea73 100644 --- a/apps/frontend/src/components/admin/PharmacyProductLink.jsx +++ b/apps/frontend/src/components/admin/PharmacyProductLink.jsx @@ -47,7 +47,7 @@ function PharmacyProductLink() { } }, [selectedPharmacy]); - // Buscar productos en la API mientras el usuario escribe + // Buscar productos en ambas APIs mientras el usuario escribe useEffect(() => { const q = productSearch.trim(); if (q.length < 2) { @@ -60,12 +60,27 @@ function PharmacyProductLink() { const timeoutId = setTimeout(async () => { setSearching(true); try { - const response = await fetch(`/api/products/search?q=${encodeURIComponent(q)}`, { - credentials: 'include', - signal: controller.signal, - }); - const data = await response.json(); - setProductResults(Array.isArray(data) ? data : []); + // Search both CIMA and Parapharmacy + const [cimaRes, paraRes] = await Promise.allSettled([ + fetch(`/api/products/search?q=${encodeURIComponent(q)}`, { + credentials: 'include', + signal: controller.signal, + }), + fetch(`/api/products/parapharmacy/search?q=${encodeURIComponent(q)}&limit=10`, { + credentials: 'include', + signal: controller.signal, + }) + ]); + + const cimaData = cimaRes.status === 'fulfilled' ? await cimaRes.value.json() : []; + const paraData = paraRes.status === 'fulfilled' ? await paraRes.value.json() : { results: [] }; + + const allResults = [ + ...(Array.isArray(cimaData) ? cimaData : []), + ...(paraData.results || []).map(p => ({ ...p, source: p.source || 'parapharmacy' })) + ]; + + setProductResults(allResults); } catch (error) { if (error.name === 'AbortError') return; console.error('Error searching products:', error); @@ -116,15 +131,15 @@ function PharmacyProductLink() { } try { - // Build identifier: source:id (e.g., openfoodfacts:9421025231209) - const identifier = selectedProduct._id - ? `${selectedProduct.source || 'openfoodfacts'}:${selectedProduct._id}` - : `${selectedProduct.source || 'openfoodfacts'}:${selectedProduct.id}`; + // Build identifier: source:id + const productId = selectedProduct._id || selectedProduct.id; + const source = selectedProduct.source || 'parapharmacy'; + const identifier = `${source}:${productId}`; const payload = { pharmacy_id: parseInt(formData.pharmacy_id), - product_source: selectedProduct.source || 'openfoodfacts', - product_off_id: selectedProduct._id || selectedProduct.id, + product_source: source, + product_off_id: productId, product_name: selectedProduct.product_name || selectedProduct.name, price: formData.price ? parseFloat(formData.price) : null, stock: formData.stock ? parseInt(formData.stock) : 0 @@ -221,10 +236,28 @@ function PharmacyProductLink() { }; const getSourceBadge = (source) => { - if (source === 'cima') { - return CIMA; - } - return OFF; + const colors = { + cima: '#2563eb', + promofarma: '#16a34a', + docmorris: '#e11d48', + primor: '#7c3aed', + parapharmacy: '#16a34a' + }; + const labels = { + cima: 'CIMA', + promofarma: 'Promofarma', + docmorris: 'DocMorris', + primor: 'Primor', + parapharmacy: 'Parafarmacia' + }; + return ( + + {labels[source] || source} + + ); }; return ( @@ -284,7 +317,7 @@ function PharmacyProductLink() {
- + {searching &&

Buscando...

} - + {productResults.length > 0 && !selectedProduct && (
{productResults.slice(0, 10).map((product) => ( -
selectProduct(product)} > {product.product_name || product.name} + {product.brand && - {product.brand}} {product.brands && - {product.brands}} - {product.quantity && ({product.quantity})} + {product.price != null && - {product.price}€} + {getSourceBadge(product.source || 'parapharmacy')}
))}
@@ -317,15 +352,16 @@ function PharmacyProductLink() {

✅ Selected: {selectedProduct.product_name || selectedProduct.name}

+ {selectedProduct.brand && `Marca: ${selectedProduct.brand} • `} {selectedProduct.brands && `Marca: ${selectedProduct.brands} • `} - {selectedProduct.quantity && `Cantidad: ${selectedProduct.quantity} • `} - {getSourceBadge(selectedProduct.source || 'openfoodfacts')} + {selectedProduct.price != null && `Precio: ${selectedProduct.price}€ • `} + {getSourceBadge(selectedProduct.source || 'parapharmacy')} {' '} - {selectedProduct._id || selectedProduct.id} + {selectedProduct._id || selectedProduct.id || selectedProduct.nregistro}

-