/* ============================================================
AUTH + APP SHELL
============================================================ */
(function(){
const {Icon,Btn,Avatar,RoleBadge,Field,Input,Banner}=window;
const {useState}=React;
/* ---------------- Login (real auth) ---------------- */
function Login(){
const {auth,go,toast}=window.useStore();
const [email,setEmail]=useState('');
const [password,setPassword]=useState('');
const [busy,setBusy]=useState(false);
const [err,setErr]=useState('');
async function doSignIn(em,pw){
if(busy) return; setBusy(true); setErr('');
const res=await auth.signIn(em,pw);
setBusy(false);
if(!res.ok){ setErr(res.error); return; }
const land=window.GOV.ROLES[res.me.role].land;
go(land);
toast({kind:'audit', icon:'shield', title:'Signed in as '+window.GOV.ROLES[res.me.role].label, desc:'Login recorded to the audit trail.'});
}
return
Sign in to BHF Hub
Partner Hospital case portal · invite-only access
{err &&
{err}
}
Invite-only access. If you're a partner hospital and need an account, contact the BHF team.
;
}
/* ---------------- App Shell ---------------- */
const TITLES={dashboard:'Dashboard',submit:'Submit New Patient',success:'Request submitted',requests:'Requests',
detail:'Request detail',queue:'My Queue',partners:'Partners',users:'Users',reports:'Reports',audit:'Audit Log',settings:'Settings'};
function AppShell({title, children}){
const {state,me,route,go,sel,navOpen,setNavOpen,dispatch,toast,auth}=window.useStore();
const [notifOpen,setNotifOpen]=useState(false);
const nav=window.GOV.NAV[me.role];
// counts
const myReqs=sel.visibleRequests();
const counts={
requests: me.role==='partner'? myReqs.length : state.requests.length,
queue: state.requests.filter(r=>r.reviewerId===me.id).length,
needs: myReqs.filter(r=>r.status==='needs_info').length,
};
// notifications: needs-info for partner; new submissions / assignments for team
const notifs = me.role==='partner'
? myReqs.filter(r=>r.status==='needs_info').map(r=>({id:r.id,t:r.id+' needs your information',d:r.patient.ref,to:r.id}))
: state.requests.filter(r=>['submitted'].includes(r.status)||r.reviewerId===me.id&&r.status==='needs_info')
.slice(0,6).map(r=>({id:r.id,t:r.id+' · '+window.GOV.STATUS[r.status].label,d:sel.hospitalName(r.hospitalId),to:r.id}));
function navItem(it){
if(it.sec) return {it.sec}
;
const active=route.screen===it.key || (route.screen==='detail'&&['requests','queue'].includes(it.key)&&false);
let count=null,alert=false;
if(it.key==='requests'&&counts.requests) count=counts.requests;
if(it.key==='queue'&&counts.queue) count=counts.queue;
if(it.key==='requests'&&me.role==='partner'&&counts.needs){count=counts.needs;alert=true;}
return go(it.key)}>
{it.label}
{count!=null && {count}}
;
}
return
setNavOpen(false)}/>
;
}
function Notif({notifs,onGo,onClose}){
return <>
Notifications
{notifs.length===0
?
You're all caught up.
: notifs.map(n=>
onGo(n.to)} style={{padding:'11px 14px',borderBottom:'1px solid var(--border-default)',cursor:'pointer',display:'flex',gap:10,alignItems:'flex-start'}} className="notif-row">
)}
>;
}
window.Login=Login;
window.AppShell=AppShell;
window.SHELL_TITLES=TITLES;
})();