Initial import: eCW Charge Validation bot and results Portal
Snapshot of the working project as of 2026-10-23 (local 2d4d4fc), one commit with no earlier history: the tracked files were de-identified first (synthetic claim ids and patient data only; see Context.md section 7). Credentials, run logs, screenshots, claim reports and client workbooks are gitignored and not included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
ba15a574ab
205 files changed
+56772
No files matched your search
@@ -0,0 +1,83 @@
|
||||
{# One claim's side panel — for the day page and a claim's history. A row
|
||||
carries its data in data-fields (tojson: escaped for the attribute) and
|
||||
data-details; the panel writes them with textContent only. #}
|
||||
<aside class="drawer" id="claim-panel" hidden>
|
||||
<div class="top"><h2 id="cp-title"></h2>
|
||||
<button type="button" class="close">Close</button></div>
|
||||
<div class="body">
|
||||
<p><span id="cp-cat"></span> <span class="note" id="cp-when"></span></p>
|
||||
<dl id="cp-fields"></dl>
|
||||
<div id="cp-details-box" hidden><h3>Conditions and changes</h3>
|
||||
<pre id="cp-details"></pre></div>
|
||||
</div>
|
||||
</aside>
|
||||
<script>
|
||||
function showClaim(tr) {
|
||||
document.querySelectorAll('tr.sel').forEach(t => t.classList.remove('sel'));
|
||||
tr.classList.add('sel');
|
||||
$('cp-title').textContent = 'Claim ' + tr.dataset.claim;
|
||||
const cat = tr.dataset.category || '';
|
||||
$('cp-cat').className = CATEGORIES.includes(cat) ? 'cat ' + cat : '';
|
||||
$('cp-cat').textContent = cat;
|
||||
$('cp-when').textContent = tr.dataset.when || '';
|
||||
const dl = $('cp-fields');
|
||||
dl.replaceChildren();
|
||||
// Only the fields that hold something: an empty field says nothing.
|
||||
for (const [header, value] of JSON.parse(tr.dataset.fields || '[]')) {
|
||||
if (!value) continue;
|
||||
const dt = document.createElement('dt');
|
||||
dt.textContent = header;
|
||||
const dd = document.createElement('dd');
|
||||
dd.textContent = value;
|
||||
dl.append(dt, dd);
|
||||
}
|
||||
const det = tr.dataset.details || '';
|
||||
$('cp-details').textContent = det;
|
||||
$('cp-details-box').hidden = !det;
|
||||
openPanel('claim-panel');
|
||||
}
|
||||
|
||||
// 10 claims a page (operator, 2026-10-15), pagers above and below.
|
||||
const PAGE_SIZE = 10;
|
||||
const allRows = [...document.querySelectorAll('tbody tr[data-claim]')];
|
||||
allRows.forEach(tr => tr.addEventListener('click', () => showClaim(tr)));
|
||||
let page = 0;
|
||||
const pageCount = () => Math.max(1, Math.ceil(allRows.length / PAGE_SIZE));
|
||||
function goToPage(n) {
|
||||
page = Math.min(Math.max(n, 0), pageCount() - 1);
|
||||
allRows.forEach((tr, i) =>
|
||||
tr.hidden = Math.floor(i / PAGE_SIZE) !== page);
|
||||
drawPagers();
|
||||
}
|
||||
function drawPagers() {
|
||||
const total = allRows.length;
|
||||
for (const id of ['pager-top', 'pager-bottom']) {
|
||||
const box = $(id);
|
||||
if (!box) continue;
|
||||
box.replaceChildren();
|
||||
if (pageCount() < 2) continue;
|
||||
const btn = (text, to, cur) => {
|
||||
const b = document.createElement('button');
|
||||
b.type = 'button'; b.textContent = text;
|
||||
if (cur) b.className = 'cur';
|
||||
b.disabled = cur || to < 0 || to >= pageCount();
|
||||
b.onclick = () => {
|
||||
goToPage(to);
|
||||
// From the bottom pager the new page starts above the window.
|
||||
if (id === 'pager-bottom')
|
||||
$('pager-top').scrollIntoView({block: 'nearest'});
|
||||
};
|
||||
box.append(b);
|
||||
};
|
||||
btn('◀ Prev', page - 1, false);
|
||||
for (let i = 0; i < pageCount(); i++) btn(String(i + 1), i, i === page);
|
||||
btn('Next ▶', page + 1, false);
|
||||
const info = document.createElement('span');
|
||||
info.className = 'info';
|
||||
info.textContent = `Showing ${page * PAGE_SIZE + 1}–` +
|
||||
`${Math.min((page + 1) * PAGE_SIZE, total)} of ${total}`;
|
||||
box.append(info);
|
||||
}
|
||||
}
|
||||
goToPage(0);
|
||||
</script>
|
||||
Reference in new issue
Block a user