import React, { useState, useEffect, useMemo, useCallback } from 'react'; import SearchBar from '../components/SearchBar'; import MedicineResults from '../components/MedicineResults'; import PharmacyList from '../components/PharmacyList'; import PharmacyMap from '../components/PharmacyMap'; import { haversineKm, getUserPosition } from '../utils/geo'; import './SearchView.css'; const suggestions = [ { name: 'Paracetamol', icon: 'medication', color: 'neutral-1' }, { name: 'Ibuprofeno', icon: 'pill', color: 'neutral-2' }, { name: 'Aspirina', icon: 'vaccines', color: 'neutral-3' }, { name: 'Omeprazol', icon: 'emergency_home', color: 'neutral-4' }, ]; function SearchView({ currentUser, onLoginRequest, initialQuery = '' }) { const [searchQuery, setSearchQuery] = useState(initialQuery); const [medicines, setMedicines] = useState([]); const [selectedMedicine, setSelectedMedicine] = useState(null); const [pharmacies, setPharmacies] = useState([]); const [loading, setLoading] = useState(false); const [userPosition, setUserPosition] = useState(null); const [positionSource, setPositionSource] = useState(null); const [sortByDistance, setSortByDistance] = useState(false); const [locating, setLocating] = useState(false); const [locationError, setLocationError] = useState(''); const [recentSearches, setRecentSearches] = useState([]); // Fetch recent searches when user is logged in useEffect(() => { if (!currentUser) { setRecentSearches([]); return; } fetch('/api/search/recent', { credentials: 'include' }) .then((r) => r.json()) .then((data) => setRecentSearches(Array.isArray(data) ? data : [])) .catch(() => setRecentSearches([])); }, [currentUser]); const saveToRecent = useCallback((medicine) => { if (!currentUser) return; fetch('/api/search/recent', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ medicine }), }).catch(() => {}); // Update local state immediately setRecentSearches((prev) => { const filtered = prev.filter((m) => m.id !== medicine.id); return [ { id: medicine.id, name: medicine.name, active_ingredient: medicine.active_ingredient, dosage: medicine.dosage, form: medicine.form, timestamp: Date.now(), }, ...filtered, ].slice(0, 10); }); }, [currentUser]); useEffect(() => { const searchMedicines = async () => { if (searchQuery.trim().length < 2) { setMedicines([]); setSelectedMedicine(null); setPharmacies([]); return; } setLoading(true); try { const response = await fetch(`/api/medicines/search?q=${encodeURIComponent(searchQuery)}`); const data = await response.json(); setMedicines(data); } catch (error) { console.error('Error searching medicines:', error); } finally { setLoading(false); } }; const timeoutId = setTimeout(searchMedicines, 300); return () => clearTimeout(timeoutId); }, [searchQuery]); useEffect(() => { const fetchPharmacies = async () => { if (!selectedMedicine) { setPharmacies([]); return; } setLoading(true); try { const response = await fetch(`/api/medicines/${selectedMedicine.id}/pharmacies`); const data = await response.json(); setPharmacies(data); } catch (error) { console.error('Error fetching pharmacies:', error); } finally { setLoading(false); } }; fetchPharmacies(); }, [selectedMedicine]); const savedLat = currentUser?.latitude; const savedLon = currentUser?.longitude; const hasSavedCoords = savedLat != null && savedLon != null; const handleSortByDistance = async () => { if (sortByDistance) { setSortByDistance(false); return; } setLocationError(''); if (hasSavedCoords) { setUserPosition({ lat: savedLat, lon: savedLon }); setPositionSource('profile'); setSortByDistance(true); // Save to search history try { fetch('/api/search-history', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ address: currentUser?.address, latitude: savedLat, longitude: savedLon, }), }); } catch (err) { console.error('Error saving search history:', err); } return; } if (userPosition) { setSortByDistance(true); return; } setLocating(true); try { const pos = await getUserPosition(); setUserPosition(pos); setPositionSource('browser'); setSortByDistance(true); // Save to search history try { fetch('/api/search-history', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'include', body: JSON.stringify({ address: 'Ubicación actual', latitude: pos.lat, longitude: pos.lon, }), }); } catch (err) { console.error('Error saving search history:', err); } } 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 solicitud de ubicación expiró'; } setLocationError(msg); } finally { setLocating(false); } }; 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]); return (
{r.dosage && `${r.dosage}`} {r.dosage && r.form && ' \u2022 '} {r.form}