Polish results, patients, and nav state

This commit is contained in:
sas.fajri
2026-04-13 15:10:36 +07:00
parent a6f9b60362
commit bc6d4fcdad
2 changed files with 118 additions and 43 deletions

116
server.js
View File

@@ -200,6 +200,14 @@ function layout(title, body, { authenticated = false, activePath = "/", subtitle
var root = document.getElementById('modal-root');
if (root) root.scrollTop = 0;
}
if (event.detail && event.detail.target && event.detail.target.classList) {
event.detail.target.classList.remove('swap-in');
void event.detail.target.offsetWidth;
event.detail.target.classList.add('swap-in');
window.setTimeout(function () {
event.detail.target.classList.remove('swap-in');
}, 240);
}
});
})();
</script>
@@ -719,7 +727,7 @@ function renderResultsTable(results, selectedResultId) {
.join("")}
</div>
</section>
<aside class="panel" id="result-detail-fragment">
<aside class="panel swap-zone" id="result-detail-fragment">
${panelHeader("Selected result", "Use the right pane for quick context without losing list position.", `<a class="btn btn-secondary" href="/results/${selected.id}">Open detail</a>`)}
<div class="stack">
<div class="card">
@@ -737,7 +745,7 @@ function renderResultsTable(results, selectedResultId) {
function renderResultDetail(result) {
return `
<section class="panel">
<section class="panel swap-zone">
${panelHeader(`${result.patient} · ${result.id}`, "Result detail with summary, status, and interpretation fields.", '<a class="btn btn-secondary" href="/results">Back to results</a>')}
<div class="grid grid-3">
<div class="card"><span class="muted">Status</span><div style="margin-top:8px">${statusBadge(result.status)}</div></div>
@@ -763,7 +771,7 @@ function renderResultDetail(result) {
function renderFpp(groups) {
return `
<div class="stack">
<div class="stack swap-zone">
<section class="panel">
${panelHeader("FPP catalog", "Filter blocks and list cards on mobile, richer panel on desktop.")}
<div class="pill-row">
@@ -822,49 +830,71 @@ function renderPatients() {
return `
<div class="stack">
<section class="panel">
${panelHeader("Patient registration", "Landing page for registration, lookup, and entry flow.")}
<div class="grid grid-3">
<div class="card">
<strong>New patient</strong>
<p class="muted">Open the registration stepper and start a fresh case.</p>
<a class="btn btn-primary" href="/orders/new/demografi">Start registration</a>
</div>
<div class="card">
<strong>Lookup</strong>
<p class="muted">Search an existing patient and reuse their visit data.</p>
<button class="btn btn-secondary" type="button">Search patient</button>
</div>
<div class="card">
<strong>QR entry</strong>
<p class="muted">Fast path for scan-based intake.</p>
<a class="btn btn-secondary" href="/orders/new/qrcode">Open QR flow</a>
</div>
${panelHeader("Patient registration", "A landing zone for registration, lookup, and intake shortcuts.", '<a class="btn btn-primary" href="/orders/new/demografi">Start registration</a>')}
<div class="grid grid-4">
${[
["Today's intake", "11", "New or updated patients"],
["Active visits", "7", "Cases linked to lab orders"],
["QR scans", "4", "Fast entry from QR code"],
["Needs review", "2", "Patients waiting verification"],
]
.map(
([label, value, hint]) => `
<article class="card metric">
<div class="kicker">
<span>${escapeHtml(label)}</span>
<span class="trend">Live</span>
</div>
<strong>${escapeHtml(value)}</strong>
<span class="muted">${escapeHtml(hint)}</span>
</article>
`,
)
.join("")}
</div>
</section>
<section class="panel">
${panelHeader("Recent patients", "A compact list that becomes cards on mobile.")}
<div class="table-wrap">
<table>
<thead>
<tr><th>Name</th><th>MRN</th><th>Gender</th><th>Last visit</th><th>Note</th></tr>
</thead>
<tbody>
${mockPatients
.map(
(person) => `
<tr>
<td><strong>${escapeHtml(person.name)}</strong></td>
<td>${escapeHtml(person.mrn)}</td>
<td>${escapeHtml(person.gender)}</td>
<td>${escapeHtml(person.lastVisit)}</td>
<td>${escapeHtml(person.note)}</td>
</tr>
`,
)
.join("")}
</tbody>
</table>
<section class="detail-grid">
<div class="panel">
${panelHeader("Quick intake", "Route into the proper entry flow without forcing the user through extra screens.")}
<div class="grid grid-2">
<div class="card">
<strong>Lookup patient</strong>
<p class="muted">Search existing records and attach them to the next order.</p>
<div class="field" style="margin-top:12px">
<label><span class="muted">MRN / name</span></label>
<input placeholder="Siti Amelia" />
</div>
<button class="btn btn-secondary" type="button" style="margin-top:12px">Search</button>
</div>
<div class="card">
<strong>New patient</strong>
<p class="muted">Jump straight into demographic capture.</p>
<div class="pill-row" style="margin-top:12px">
<a class="pill" href="/orders/new/demografi">Demografi</a>
<a class="pill" href="/orders/new/qrcode">QR entry</a>
</div>
<div class="note-box" style="margin-top:14px">Use the registration stepper when the patient is not yet in the system.</div>
</div>
</div>
</div>
<aside class="panel">
${panelHeader("Recent patients", "A compact list that stays readable on mobile and still works as a table on desktop.")}
<div class="mini-list">
${mockPatients
.map(
(person) => `
<div class="mini-item">
<div>
<strong>${escapeHtml(person.name)}</strong>
<p>${escapeHtml(person.mrn)} · ${escapeHtml(person.gender)}</p>
</div>
<span class="pill">${escapeHtml(person.lastVisit)}</span>
</div>
`,
)
.join("")}
</div>
</aside>
</section>
</div>
`;