// portal-canjes.jsx — Canje tracker (patient) + Operator submission queue const { useState, useMemo } = React; // ── Helpers ─────────────────────────────────────────────────────────────────── function getProgramById(id) { return (window.LAB_PROGRAMS || []).find(p => p.id === id); } function getLabById(id) { return (window.LABS || []).find(l => l.id === id); } function getPatientById(id) { return (window.PATIENTS || []).find(p => p.id === id); } function programTypeLabel(buyQty, freeQty) { return `${buyQty}+${freeQty}`; } // ── EnrollModal — browse available programs to join ─────────────────────────── function EnrollModal({ patient, enrollments, onEnroll, onClose }) { const C = window.C; const [labFilter, setLabFilter] = useState('all'); const enrolledIds = enrollments.map(e => e.programId); const available = (window.LAB_PROGRAMS || []).filter(p => !enrolledIds.includes(p.id)); const filtered = labFilter === 'all' ? available : available.filter(p => p.labId === labFilter); return ( {/* Lab filter chips */}
{['all', 'lafage', 'lancasco', 'denk', 'pharmaetica'].map(id => { const lab = id === 'all' ? null : getLabById(id); const active = labFilter === id; return ( ); })}
{filtered.map(prog => { const lab = getLabById(prog.labId); return (
{prog.medicine}
{prog.condition}
{programTypeLabel(prog.buyQty, prog.freeQty)}
PROG.
); })} {filtered.length === 0 && }
); } // ── CanjeCard — single enrolled program ─────────────────────────────────────── function CanjeCard({ enrollment, onRegisterPurchase }) { const C = window.C; const prog = getProgramById(enrollment.programId); const lab = getLabById(prog?.labId); if (!prog || !lab) return null; const total = prog.buyQty; const logged = enrollment.purchasesLogged; const pending = enrollment.purchasesPending; const effective = logged + pending; // shown as total purchases const isReady = enrollment.rewardsPending > 0; const pct = Math.min((effective / total) * 100, 100); return (
{/* Header row */}
{prog.medicine}
{programTypeLabel(prog.buyQty, prog.freeQty)} {pending > 0 && ( {pending} en espera de portal )}
{/* Program ratio badge */}
{programTypeLabel(prog.buyQty, prog.freeQty)}
CANJE
{/* Progress */} {isReady ? (
¡Canje disponible!
{enrollment.rewardsPending} caja{enrollment.rewardsPending > 1 ? 's' : ''} gratis lista{enrollment.rewardsPending > 1 ? 's' : ''} para recoger
) : (
{effective} / {total} compras registradas {total - effective > 0 ? `Falta${total - effective > 1 ? 'n' : ''} ${total - effective}` : 'Completo'}
)} {/* Condition tag */}
{prog.condition}
{/* Actions */} {!isReady && ( )}
); } // ── RegisterPurchaseModal ───────────────────────────────────────────────────── function RegisterPurchaseModal({ enrollment, prog, patient, onConfirm, onClose }) { const C = window.C; const [date, setDate] = useState(new Date().toISOString().split('T')[0]); const lab = getLabById(prog?.labId); return (
{prog?.medicine}
Programa {prog?.buyQty}+{prog?.freeQty} · {lab?.name}
Fecha de compra en Farmacia Santos
setDate(e.target.value)} style={{ width: '100%', padding: '10px 14px', borderRadius: 10, border: `1.5px solid ${C.border}`, fontFamily: 'inherit', fontSize: 14, color: C.text1, background: C.bg, }} />
¿Cómo funciona? Un operador de la farmacia enviará esta compra al portal de {lab?.name}. Una vez confirmada, tu progreso se actualizará automáticamente.
); } // ── CanjesTab — patient-facing view ────────────────────────────────────────── function CanjesTab({ patient, enrollments, onAddEnrollment, onRegisterPurchase }) { const C = window.C; const [showEnroll, setShowEnroll] = useState(false); const [regTarget, setRegTarget] = useState(null); // { enrollment, prog } const myEnrollments = enrollments.filter(e => e.customerId === patient.id); const readyCanjes = myEnrollments.filter(e => e.rewardsPending > 0); const inProgress = myEnrollments.filter(e => e.rewardsPending === 0); return (
{/* Ready banner */} {readyCanjes.length > 0 && (
{readyCanjes.length === 1 ? '¡Tienes 1 canje listo!' : `¡Tienes ${readyCanjes.length} canjes listos!`}
Pasa a Farmacia Santos para recogerlos
)} {/* Ready canjes */} {readyCanjes.length > 0 && ( <> LISTOS PARA RECOGER {readyCanjes.map(e => ( setRegTarget({ enr, prog })} /> ))} )} {/* In-progress */} {inProgress.length > 0 && ( <> 0 ? 8 : 0 }}>EN PROGRESO {inProgress.map(e => ( setRegTarget({ enr, prog })} /> ))} )} {myEnrollments.length === 0 && ( )} {/* Enroll CTA */} {/* Modals */} {showEnroll && ( { onAddEnrollment(patient.id, prog); setShowEnroll(false); }} onClose={() => setShowEnroll(false)} /> )} {regTarget && ( { onRegisterPurchase(enr.id, date); setRegTarget(null); }} onClose={() => setRegTarget(null)} /> )}
); } // ── OperatorQueue — grouped submission list by lab ──────────────────────────── function OperatorQueue({ submissions, enrollments, onMarkSubmitted }) { const C = window.C; const [confirmed, setConfirmed] = useState(null); const pending = submissions.filter(s => !s.submittedToPortal); const byLab = {}; pending.forEach(s => { const prog = getProgramById(s.programId); if (!prog) return; if (!byLab[s.labId]) byLab[s.labId] = []; byLab[s.labId].push({ ...s, prog }); }); const handleMark = (sub) => { setConfirmed(null); onMarkSubmitted(sub.id); }; return (
{/* Summary */}
ENVÍOS PENDIENTES
{pending.length}
en {Object.keys(byLab).length} portal{Object.keys(byLab).length > 1 ? 'es' : ''}
Última actualización: Hoy 5:00 AM
{pending.length === 0 && } {/* Per-lab groups */} {Object.entries(byLab).map(([labId, items]) => { const lab = getLabById(labId); if (!lab) return null; return (
{/* Lab header */}
{lab.name}
{items.length} envío{items.length > 1 ? 's' : ''} pendiente{items.length > 1 ? 's' : ''}
Abrir portal ↗
{/* Submission rows */} {items.map(sub => { const patient = getPatientById(sub.customerId); const enr = enrollments.find(e => e.id === sub.enrollmentId); if (!patient) return null; return (
{/* Avatar */}
{patient.iniciales}
{patient.nombre}
{patient.dni}
{sub.prog.medicine}
Compra: {new Date(sub.date).toLocaleDateString('es-HN', { day: 'numeric', month: 'short' })} {enr && ` · Progreso: ${enr.purchasesLogged + enr.purchasesPending}/${sub.prog.buyQty}`}
); })}
); })} {/* Confirm modal */} {confirmed && ( setConfirmed(null)} title="Confirmar envío al portal"> {(() => { const patient = getPatientById(confirmed.customerId); const lab = getLabById(confirmed.labId); return ( <>
{confirmed.prog.medicine}
{patient?.nombre} · {patient?.dni}
Portal: {lab?.name} · {new Date(confirmed.date).toLocaleDateString('es-HN')}
¿Confirmás que ya registraste esta compra en el portal de {lab?.name}? El progreso del cliente se actualizará.
); })()}
)}
); } Object.assign(window, { CanjesTab, OperatorQueue });