115 lines
3.6 KiB
React
115 lines
3.6 KiB
React
import React, { useEffect, useState } from 'react';
|
|
import './MedicineResults.css';
|
|
import {
|
|
pushSupported,
|
|
isSubscribedLocally,
|
|
subscribeToPush,
|
|
unsubscribeFromPush,
|
|
} from '../utils/notifications.js';
|
|
|
|
function MedicineResults({ medicines, onSelect, query, currentUser, onLoginRequest }) {
|
|
if (medicines.length === 0 && query.length >= 2) {
|
|
return (
|
|
<div className="no-results">
|
|
<p>No se encontraron medicamentos para "{query}"</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="medicine-results">
|
|
{medicines.map((medicine) => (
|
|
<MedicineCard
|
|
key={medicine.nregistro || medicine.id}
|
|
medicine={medicine}
|
|
onSelect={onSelect}
|
|
currentUser={currentUser}
|
|
onLoginRequest={onLoginRequest}
|
|
/>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function MedicineCard({ medicine, onSelect, currentUser, onLoginRequest }) {
|
|
const nregistro = medicine.nregistro || medicine.id;
|
|
const [subscribed, setSubscribed] = useState(() => isSubscribedLocally(nregistro));
|
|
const [busy, setBusy] = useState(false);
|
|
const [error, setError] = useState(null);
|
|
const supported = pushSupported();
|
|
|
|
useEffect(() => {
|
|
setSubscribed(isSubscribedLocally(nregistro));
|
|
}, [nregistro]);
|
|
|
|
async function handleBell(e) {
|
|
e.stopPropagation();
|
|
if (!currentUser) {
|
|
onLoginRequest?.();
|
|
return;
|
|
}
|
|
if (!supported) {
|
|
setError('Las notificaciones requieren iOS 16.4+ y este sitio instalado como app (Compartir → Añadir a Pantalla de Inicio).');
|
|
return;
|
|
}
|
|
if (busy) return;
|
|
setBusy(true);
|
|
setError(null);
|
|
try {
|
|
if (subscribed) {
|
|
await unsubscribeFromPush(nregistro);
|
|
setSubscribed(false);
|
|
} else {
|
|
await subscribeToPush(nregistro, medicine.name);
|
|
setSubscribed(true);
|
|
}
|
|
} catch (err) {
|
|
console.error('[notify] toggle failed:', err);
|
|
setError(err.message || 'No se pudo actualizar la suscripción');
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="medicine-card" onClick={() => onSelect(medicine)}>
|
|
<div className="medicine-card-header">
|
|
<h3>{medicine.name}</h3>
|
|
<button
|
|
type="button"
|
|
className={`notify-bell${subscribed && currentUser ? ' notify-bell--on' : ''}${!currentUser ? ' notify-bell--locked' : ''}`}
|
|
onClick={handleBell}
|
|
disabled={busy}
|
|
aria-pressed={subscribed && !!currentUser}
|
|
aria-label={
|
|
!currentUser
|
|
? 'Inicia sesión para activar notificaciones'
|
|
: subscribed
|
|
? 'Desactivar notificaciones para este medicamento'
|
|
: 'Notificarme cuando esté disponible'
|
|
}
|
|
title={
|
|
!currentUser
|
|
? 'Inicia sesión para activar notificaciones'
|
|
: subscribed
|
|
? 'Notificaciones activadas — clic para desactivar'
|
|
: 'Notificarme cuando este medicamento esté en una farmacia'
|
|
}
|
|
>
|
|
{subscribed && currentUser ? '🔔' : '🔕'}
|
|
</button>
|
|
</div>
|
|
<div className="medicine-card-body">
|
|
<p><strong>Principio Activo:</strong> {medicine.active_ingredient}</p>
|
|
<p><strong>Dosis:</strong> {medicine.dosage} • <strong>Forma:</strong> {medicine.form}</p>
|
|
{error && <p className="notify-error" onClick={e => e.stopPropagation()}>{error}</p>}
|
|
</div>
|
|
<div className="medicine-card-footer">
|
|
<span className="view-pharmacies">Ver farmacias →</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default MedicineResults;
|