Spaces:
Sleeping
Sleeping
| <html lang="en" data-bs-theme="dark"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Second Life — Clinical Trial Matching</title> | |
| <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> | |
| <style> | |
| body{background:linear-gradient(135deg,#0d1117 0%,#161b22 100%);min-height:100vh;} | |
| .hero-title{font-size:3rem;font-weight:800;background:linear-gradient(90deg,#58a6ff,#79c0ff);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;} | |
| .portal-card{background:#161b22;border:1px solid #30363d;border-radius:12px;padding:2rem;} | |
| .form-control,.form-select{background:#0d1117;border-color:#30363d;color:#e6edf3;} | |
| .form-control:focus,.form-select:focus{background:#0d1117;border-color:#58a6ff;color:#e6edf3;box-shadow:0 0 0 .2rem rgba(88,166,255,.25);} | |
| .nav-tabs .nav-link{color:#8b949e;border-color:transparent;} | |
| .nav-tabs .nav-link.active{color:#e6edf3;background:#161b22;border-color:#30363d #30363d #161b22;} | |
| .err{color:#f85149;font-size:.85rem;min-height:1.2rem;} | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container py-5"> | |
| <div class="text-center mb-5"> | |
| <div class="text-primary mb-2" style="font-size:2rem">⬡</div> | |
| <h1 class="hero-title">Second Life</h1> | |
| <p class="text-secondary fs-5 mb-1">AI-Powered Clinical Trial Matching</p> | |
| <p class="text-muted small">Connecting patients with life-changing research opportunities</p> | |
| </div> | |
| <div class="row g-4 justify-content-center"> | |
| <!-- Patient Portal --> | |
| <div class="col-lg-5"> | |
| <div class="portal-card"> | |
| <div class="text-center mb-3" style="font-size:2.5rem">🧑⚕️</div> | |
| <h4 class="text-center mb-1">Patient Portal</h4> | |
| <p class="text-muted text-center small mb-3">Find clinical trials matched to your conditions</p> | |
| <ul class="nav nav-tabs mb-3" id="patientTabs"> | |
| <li class="nav-item"><a class="nav-link active" href="#" data-pt="p-login">Login</a></li> | |
| <li class="nav-item"><a class="nav-link" href="#" data-pt="p-register">Register</a></li> | |
| </ul> | |
| <!-- Login --> | |
| <div id="p-login"> | |
| <input type="text" class="form-control mb-2" id="pl-user" placeholder="Username"> | |
| <input type="password" class="form-control mb-3" id="pl-pass" placeholder="Password"> | |
| <div class="err mb-2" id="pl-err"></div> | |
| <button class="btn btn-primary w-100" onclick="patientLogin()">Login as Patient</button> | |
| <p class="text-muted text-center mt-2 small">Demo: john_doe / pass123</p> | |
| </div> | |
| <!-- Register --> | |
| <div id="p-register" style="display:none"> | |
| <div class="row g-2 mb-2"> | |
| <div class="col"><input type="text" class="form-control form-control-sm" id="pr-fn" placeholder="First Name"></div> | |
| <div class="col"><input type="text" class="form-control form-control-sm" id="pr-ln" placeholder="Last Name"></div> | |
| </div> | |
| <div class="row g-2 mb-2"> | |
| <div class="col"><input type="date" class="form-control form-control-sm" id="pr-dob"></div> | |
| <div class="col"> | |
| <select class="form-select form-select-sm" id="pr-gender"> | |
| <option value="">Gender</option> | |
| <option value="M">Male</option> | |
| <option value="F">Female</option> | |
| <option value="O">Other</option> | |
| </select> | |
| </div> | |
| </div> | |
| <input type="text" class="form-control form-control-sm mb-2" id="pr-addr" placeholder="Address (123 Main St Boston MA 02101)"> | |
| <input type="text" class="form-control form-control-sm mb-2" id="pr-user" placeholder="Username"> | |
| <input type="password" class="form-control form-control-sm mb-3" id="pr-pass" placeholder="Password"> | |
| <div class="err mb-2" id="pr-err"></div> | |
| <button class="btn btn-primary w-100" onclick="patientRegister()">Create Patient Account</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Hospital Portal --> | |
| <div class="col-lg-5"> | |
| <div class="portal-card"> | |
| <div class="text-center mb-3" style="font-size:2.5rem">🏥</div> | |
| <h4 class="text-center mb-1">Hospital / Research Portal</h4> | |
| <p class="text-muted text-center small mb-3">Find eligible patients for your clinical trials</p> | |
| <ul class="nav nav-tabs mb-3" id="hospitalTabs"> | |
| <li class="nav-item"><a class="nav-link active" href="#" data-ht="h-login">Login</a></li> | |
| <li class="nav-item"><a class="nav-link" href="#" data-ht="h-register">Register</a></li> | |
| </ul> | |
| <!-- Login --> | |
| <div id="h-login"> | |
| <input type="text" class="form-control mb-2" id="hl-user" placeholder="Username"> | |
| <input type="password" class="form-control mb-3" id="hl-pass" placeholder="Password"> | |
| <div class="err mb-2" id="hl-err"></div> | |
| <button class="btn btn-success w-100" onclick="hospitalLogin()">Login as Hospital</button> | |
| <p class="text-muted text-center mt-2 small">Demo: mgh / mgh123</p> | |
| </div> | |
| <!-- Register --> | |
| <div id="h-register" style="display:none"> | |
| <input type="text" class="form-control form-control-sm mb-2" id="hr-name" placeholder="Hospital / Institution Name"> | |
| <input type="text" class="form-control form-control-sm mb-2" id="hr-loc" placeholder="Location (City, ST) e.g. Boston, MA"> | |
| <input type="text" class="form-control form-control-sm mb-2" id="hr-conds" | |
| placeholder="Research conditions (comma-separated, e.g. diabetes, hypertension)"> | |
| <input type="text" class="form-control form-control-sm mb-2" id="hr-user" placeholder="Username"> | |
| <input type="password" class="form-control form-control-sm mb-3" id="hr-pass" placeholder="Password"> | |
| <div class="err mb-2" id="hr-err"></div> | |
| <button class="btn btn-success w-100" onclick="hospitalRegister()">Create Hospital Account</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <p class="text-center text-muted small mt-4">DSCI 5260 | Group 7 — Second Life Clinical Trial Matching</p> | |
| </div> | |
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script> | |
| <script> | |
| // Enter key submit helpers | |
| function _onEnter(inputId, fn) { | |
| document.getElementById(inputId).addEventListener('keydown', e => { if(e.key==='Enter') fn(); }); | |
| } | |
| document.addEventListener('DOMContentLoaded', () => { | |
| _onEnter('pl-pass', patientLogin); | |
| _onEnter('pl-user', patientLogin); | |
| _onEnter('pr-pass', patientRegister); | |
| _onEnter('hl-pass', hospitalLogin); | |
| _onEnter('hl-user', hospitalLogin); | |
| _onEnter('hr-pass', hospitalRegister); | |
| }); | |
| // Tab switching | |
| document.querySelectorAll('#patientTabs .nav-link').forEach(a => { | |
| a.addEventListener('click', e => { | |
| e.preventDefault(); | |
| document.querySelectorAll('#patientTabs .nav-link').forEach(x => x.classList.remove('active')); | |
| a.classList.add('active'); | |
| document.getElementById('p-login').style.display = a.dataset.pt === 'p-login' ? '' : 'none'; | |
| document.getElementById('p-register').style.display = a.dataset.pt === 'p-register' ? '' : 'none'; | |
| }); | |
| }); | |
| document.querySelectorAll('#hospitalTabs .nav-link').forEach(a => { | |
| a.addEventListener('click', e => { | |
| e.preventDefault(); | |
| document.querySelectorAll('#hospitalTabs .nav-link').forEach(x => x.classList.remove('active')); | |
| a.classList.add('active'); | |
| document.getElementById('h-login').style.display = a.dataset.ht === 'h-login' ? '' : 'none'; | |
| document.getElementById('h-register').style.display = a.dataset.ht === 'h-register' ? '' : 'none'; | |
| }); | |
| }); | |
| async function patientLogin() { | |
| const u = document.getElementById('pl-user').value.trim(); | |
| const p = document.getElementById('pl-pass').value; | |
| const e = document.getElementById('pl-err'); | |
| e.textContent = ''; | |
| if (!u || !p) { e.textContent = 'Enter username and password'; return; } | |
| const r = await post('/auth/patient/login', {username:u, password:p}); | |
| if (r.ok) location.href = '/patient'; else e.textContent = (await r.json()).error || 'Login failed'; | |
| } | |
| async function patientRegister() { | |
| const body = { | |
| username: document.getElementById('pr-user').value.trim(), | |
| password: document.getElementById('pr-pass').value, | |
| first_name: document.getElementById('pr-fn').value.trim(), | |
| last_name: document.getElementById('pr-ln').value.trim(), | |
| dob: document.getElementById('pr-dob').value, | |
| gender: document.getElementById('pr-gender').value, | |
| address: document.getElementById('pr-addr').value.trim(), | |
| }; | |
| const e = document.getElementById('pr-err'); | |
| e.textContent = ''; | |
| if (!body.username || !body.password) { e.textContent = 'Username and password required'; return; } | |
| const r = await post('/auth/patient/register', body); | |
| if (r.ok) location.href = '/patient'; else e.textContent = (await r.json()).error || 'Registration failed'; | |
| } | |
| async function hospitalLogin() { | |
| const u = document.getElementById('hl-user').value.trim(); | |
| const p = document.getElementById('hl-pass').value; | |
| const e = document.getElementById('hl-err'); | |
| e.textContent = ''; | |
| if (!u || !p) { e.textContent = 'Enter username and password'; return; } | |
| const r = await post('/auth/hospital/login', {username:u, password:p}); | |
| if (r.ok) location.href = '/hospital'; else e.textContent = (await r.json()).error || 'Login failed'; | |
| } | |
| async function hospitalRegister() { | |
| const condsRaw = document.getElementById('hr-conds').value.trim(); | |
| const body = { | |
| username: document.getElementById('hr-user').value.trim(), | |
| password: document.getElementById('hr-pass').value, | |
| hospital_name: document.getElementById('hr-name').value.trim(), | |
| location: document.getElementById('hr-loc').value.trim(), | |
| research_conditions: condsRaw ? condsRaw.split(',').map(s => s.trim().toLowerCase()).filter(Boolean) : [], | |
| }; | |
| const e = document.getElementById('hr-err'); | |
| e.textContent = ''; | |
| if (!body.username || !body.password || !body.hospital_name) { e.textContent = 'All fields required'; return; } | |
| const r = await post('/auth/hospital/register', body); | |
| if (r.ok) location.href = '/hospital'; else e.textContent = (await r.json()).error || 'Registration failed'; | |
| } | |
| function post(url, body) { | |
| return fetch(url, {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(body)}); | |
| } | |
| </script> | |
| </body> | |
| </html> | |