import React, { useState, useEffect, useMemo } from 'react'; import PharmacyMap from '../components/PharmacyMap'; import PharmacyList from '../components/PharmacyList'; import { haversineKm, getUserPosition, hasCachedPosition } from '../utils/geo'; import './ProductView.css'; export default function ProductView({ source, id, onBack }) { const [product, setProduct] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [pharmacies, setPharmacies] = useState([]); const [loadingPharmacies, setLoadingPharmacies] = useState(false); const [sortByDistance, setSortByDistance] = useState(false); const [userPosition, setUserPosition] = useState(null); const [positionSource, setPositionSource] = useState(null); const [locating, setLocating] = useState(false); const [locationError, setLocationError] = useState(''); const hasSavedCoords = product?.latitude != null && product?.longitude != null; const displayedPharmacies = useMemo(() => { if (!sortByDistance || !userPosition) return pharmacies; return [...pharmacies].sort((a, b) => { if (a.latitude == null || a.longitude == null) return 1; if (b.latitude == null || b.longitude == null) return -1; return ( haversineKm(userPosition.lat, userPosition.lon, a.latitude, a.longitude) - haversineKm(userPosition.lat, userPosition.lon, b.latitude, b.longitude) ); }); }, [pharmacies, sortByDistance, userPosition]); const handleSortByDistance = async () => { if (sortByDistance) { setSortByDistance(false); return; } setLocationError(''); setLocating(true); try { const pos = await getUserPosition(); setUserPosition(pos); setPositionSource('browser'); setSortByDistance(true); } catch (err) { let msg = 'No se pudo obtener tu ubicación'; if (err && typeof err.code === 'number') { if (err.code === 1) msg = 'Permiso de ubicación denegado.'; else if (err.code === 2) msg = 'Ubicación no disponible.'; else if (err.code === 3) msg = 'La ubicación tardó demasiado.'; } setLocationError(msg); } finally { setLocating(false); } }; useEffect(() => { loadProduct(); }, [source, id]); async function loadProduct() { setLoading(true); setError(null); setPharmacies([]); try { // Use parapharmacy endpoint for all non-CIMA sources const isCima = source === 'cima'; const apiUrl = isCima ? `/api/products/${source}/${id}` : `/api/products/parapharmacy/${id}`; const response = await fetch(apiUrl); if (!response.ok) { throw new Error('Producto no encontrado'); } const data = await response.json(); setProduct(data); loadPharmacies(source, data.id || data._id); } catch (err) { setError(err.message); } finally { setLoading(false); } } async function loadPharmacies(productSource, productId) { setLoadingPharmacies(true); try { const response = await fetch(`/api/products/${productSource}/${productId}/pharmacies`); if (response.ok) { const data = await response.json(); setPharmacies(data); } } catch { // Pharmacies are optional — don't block on failure } finally { setLoadingPharmacies(false); } } if (loading) { return (
Cargando...
); } if (error) { return (
{error}
); } if (!product) return null; const isCima = product.source === 'cima'; const isParapharmacy = product.source !== 'cima'; const sourceColor = isCima ? '#2563eb' : '#16a34a'; const sourceLabel = isCima ? 'CIMA' : 'Parafarmacia'; return (
{product.image_url && ( {product.name} )} {sourceLabel}

{product.name}

{product.brand}

{isCima ? ( <> {product.active_ingredient && ( )} {product.dosage && ( )} {product.form && ( )} {product.prescription && ( )} {product.commercialized !== undefined && ( )} ) : ( <> {product.price && ( )} {product.original_price && product.original_price > product.price && ( )} {product.category && ( )} {product.brand && ( )} {product.source_url && ( )} )}
{loadingPharmacies ? (
Cargando farmacias...
) : pharmacies.length > 0 ? ( <>

Disponible en {pharmacies.length} {pharmacies.length === 1 ? 'farmacia' : 'farmacias'}

{sortByDistance && positionSource && ( Usando tu ubicación )} {locationError && ( {locationError} )}
) : null}
); } function DetailRow({ label, value }) { return (
{label} {value}
); }