Missing files from commit
Run Tests on Branches / Frontend Tests (push) Has been cancelled
Run Tests on Branches / Backend Tests (push) Has been cancelled

This commit is contained in:
Antoni Nuñez Romeu
2026-07-07 17:44:36 +02:00
parent 7eb791f181
commit a58ce306bf
10 changed files with 497 additions and 126 deletions
+8 -2
View File
@@ -14,7 +14,7 @@ const iconMap = {
),
};
function AlertsView({ onNotificationChange }) {
function AlertsView({ onNotificationChange, onNavigateToMedicine }) {
const [availability, setAvailability] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
@@ -122,7 +122,13 @@ function AlertsView({ onNotificationChange }) {
{iconMap[cardIcon]}
</div>
<div className="alert-info">
<h3 className="alert-title">{alert.medicine_name || alert.medicine_nregistro}</h3>
<h3
className="alert-title"
style={{ cursor: 'pointer', textDecoration: 'underline', color: 'var(--primary, #6750a4)' }}
onClick={() => onNavigateToMedicine?.(alert.medicine_name || alert.medicine_nregistro)}
>
{alert.medicine_name || alert.medicine_nregistro}
</h3>
{alert.scope === 'pharmacy' ? (
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.25rem', marginTop: '0.25rem' }}>
<span className={`alert-badge alert-badge--${cardColor}`} style={{ width: 'fit-content' }}>
+21
View File
@@ -313,6 +313,27 @@
.location-error {
color: var(--error);
font-size: 0.85rem;
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
}
.retry-location-btn {
background: var(--error);
color: white;
border: none;
padding: 0.25rem 0.6rem;
border-radius: var(--radius);
font-size: 0.8rem;
font-weight: 600;
cursor: pointer;
white-space: nowrap;
transition: opacity 0.15s;
}
.retry-location-btn:hover {
opacity: 0.85;
}
.location-source {
+24 -6
View File
@@ -3,7 +3,7 @@ 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 { haversineKm, getUserPosition, hasCachedPosition } from '../utils/geo';
import './SearchView.css';
const suggestions = [
@@ -26,6 +26,15 @@ function SearchView({ currentUser, onLoginRequest, initialQuery = '' }) {
const [locationError, setLocationError] = useState('');
const [recentSearches, setRecentSearches] = useState([]);
// Precache position on mount — makes first "sort by distance" nearly instant
useEffect(() => {
if (hasCachedPosition()) {
getUserPosition().then(pos => {
setUserPosition(pos);
}).catch(() => {});
}
}, []);
// Fetch recent searches when user is logged in
useEffect(() => {
if (!currentUser) {
@@ -59,7 +68,7 @@ function SearchView({ currentUser, onLoginRequest, initialQuery = '' }) {
timestamp: Date.now(),
},
...filtered,
].slice(0, 10);
].slice(0, 5);
});
}, [currentUser]);
@@ -139,6 +148,7 @@ function SearchView({ currentUser, onLoginRequest, initialQuery = '' }) {
}
if (userPosition) {
setSortByDistance(true);
setPositionSource('cached');
return;
}
setLocating(true);
@@ -165,9 +175,9 @@ function SearchView({ currentUser, onLoginRequest, initialQuery = '' }) {
} 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ó';
if (err.code === 1) msg = 'Permiso de ubicación denegado. Permite el acceso a la ubicación en tu navegador.';
else if (err.code === 2) msg = 'Ubicación no disponible. Verifica que el GPS esté activado.';
else if (err.code === 3) msg = 'La ubicación tardó demasiado. Intenta de nuevo o verifica tu conexión.';
}
setLocationError(msg);
} finally {
@@ -316,8 +326,16 @@ function SearchView({ currentUser, onLoginRequest, initialQuery = '' }) {
{sortByDistance && positionSource === 'profile' && (
<span className="location-source">Usando tu dirección guardada</span>
)}
{sortByDistance && positionSource === 'cached' && (
<span className="location-source">Usando ubicación reciente</span>
)}
{locationError && (
<span className="location-error">{locationError}</span>
<span className="location-error">
{locationError}
<button className="retry-location-btn" onClick={handleSortByDistance}>
Reintentar
</button>
</span>
)}
</div>
)}