Clinical Console 24

RNI Clinical Console - Rev 24

Clinical Console

Prioritized Action Queue

Epic: Connected
AI Council: 6/6 Online
HIPAA: Compliant
Next Action Due 3:42
Patient Alerts (2)
Marcus Johnson — HRV Critical
Room 204A • MDD • Day 12
3:42
P Dr. Peterson detected HRV dropped below 40ms threshold
HRV declined 34% in last 2 hours, matching pre-crisis baseline. Vitals: HR 92, BP 138/88, SpO2 97%.
Rachel Davis — Missed Check-ins
Room 203B • SUD • Day 8
12:18
O Dr. Olivia flagged behavioral shift — engagement down 50%
Missed 2 scheduled check-ins. Sleep disrupted (3.2 hrs vs 7.1 baseline). Room check recommended.
Scheduled Care (4)
James Wilson — 2pm Vitals
Room 201A • Anxiety • Day 5
45:00
Routine vitals check. Patient stable, medication adherence 100%.
Sarah Chen — Med Administration
Room 205B • Step-Down • Day 3
1:15:00
Scheduled medication: Sertraline 50mg. Verify patient ID and allergies before administration.
David Park — Wound Care
Room 208A • Post-Op • Day 2
2:30:00
Dressing change for surgical site. Document wound appearance and drainage.
Emily Torres — Ambulation
Room 202B • Recovery • Day 4
3:00:00
Assisted ambulation in hallway. PT cleared for 50ft walk with assist x1.
Completed This Shift (3)
Morning Vitals Round
8 patients • Completed 7:45am
Done
Shift Handoff Received
From: Night Shift RN M. Garcia
Done
Shift Handoffs Required (2)
Unit 2-East Handoff Pending
3pm-11pm Shift • 6 patients
8:42
W Dr. Williams — 2 high-acuity patients flagged for detailed handoff
Incoming RN J. Martinez arriving at 2:45pm. Marcus Johnson (204A) and Rachel Davis (203B) require SBAR briefing.
Sarah Chen — Step-Down Transfer
Room 205B → Room 112 (Gen Med)
45:00
Patient cleared for step-down. Coordinate bed assignment with Gen Med charge nurse. Transport scheduled.
Staffing & Resources (3)
Evening Shift Coverage Gap
3pm-11pm • 1 RN short
1:30:00
T Dr. Taylor — Predicted patient load: 9 (current staffing ratio 1:5)
RN K. Thompson called out. Float pool has 2 available. Recommend adjusting assignments or calling in PRN.
Bed Board Update
Unit Capacity: 12/16 (75%)
2:00:00
2 discharges expected today. 1 admission pending from ED. Update bed board status.
Supply Restock Request
IV supplies, wound care kits
4:00:00
Floor stock below par level. Submit supply request to materials management.
Completed This Shift (2)
Morning Huddle
0730 • 8 attendees
Done
Assignment Sheet Posted
Day Shift Coverage Confirmed
Done
Clinical Decisions Required (2)
Marcus Johnson — Crisis Protocol?
Room 204A • MDD • Day 12
3:42
C Dr. Chen — VETO flag: Confirm clinical necessity before protocol activation
HRV critical (34% decline). Dr. Peterson recommends crisis protocol. Review biometrics and confirm or modify intervention plan.
Rachel Davis — Med Adjustment?
Room 203B • SUD • Day 8
45m
O Dr. Olivia suggests PRN anxiolytic given behavioral patterns
Engagement down 50%, sleep disrupted. Consider PRN order or therapy session increase. Current meds: Naltrexone 50mg daily.
Notes & Orders (3)
James Wilson — Progress Note
Room 201A • Day 5 Summary
2h
W Dr. Williams auto-drafted S.O.A.P. note ready for review
AI-generated note synthesizes: stable vitals, 100% med adherence, PHQ-9 improved 4 pts. Review and sign.
Emily Torres — Discharge Orders
Room 202B • Ready for D/C
3h
T Dr. Taylor — All discharge criteria met. 30-day readmission risk: 8%
Patient stable 48 hrs. Discharge summary drafted. Sign orders and prescriptions.
Lab Results — 3 Pending Review
Wilson, Park, Torres
4:00:00
Morning labs resulted. All within normal limits. Acknowledge to clear inbox.
Completed Today (2)
Morning Rounds
8 patients seen • 2 hrs 15 min
Done
Sarah Chen — D/C Summary Signed
Transfer to Gen Med approved
Done
Discharge Planning (2)
Emily Torres — Family Meeting
Room 202B • Discharge Today
1:30:00
W Dr. Williams — Family arriving 2pm for discharge education
Coordinate discharge: Med reconciliation complete. Home health referral pending. Family needs aftercare instructions.
Sarah Chen — Insurance Auth
Room 205B • Transfer Pending
2:00:00
Transfer to Gen Med requires prior auth update. Current auth expires today. Contact payer for extension.
Care Coordination (3)
Marcus Johnson — Outpatient Setup
Room 204A • Anticipated D/C Day 14
48:00:00
Begin discharge planning. Schedule outpatient psych follow-up and arrange transportation to appointments.
James Wilson — Social Work Consult
Room 201A • Housing Needs
24:00:00
Patient reports unstable housing. Initiate social work referral for community resources.
Weekly Utilization Review
8 patients • Due Friday
72:00:00
Prepare utilization data for insurance review. Document continued stay justification for 3 patients.
Completed This Week (2)
David Park — Insurance Approved
5-day extension authorized
Done
Rachel Davis — Family Call
Treatment update provided
Done
Escalations & Compliance (2)
Marcus Johnson — Protocol Override
Room 204A • Requires Authorization
3:42
C Dr. Chen — VETO ACTIVE: Crisis protocol requires supervisor authorization
AI Council recommends crisis intervention. Dr. Chen flagged for supervisor review due to high-risk patient history. Authorize or modify.
Staffing Critical — Unit 2-East
Evening Shift • 1 RN Short
1h 30m
T Dr. Taylor — Patient acuity high. Unsafe staffing ratio predicted if unfilled.
Charge Nurse escalated staffing gap. Float pool exhausted. Approve overtime or initiate agency call.
Unit Oversight (3)
Daily Compliance Report
All Units • Due EOD
4h
C Dr. Chen — Auto-generated compliance summary ready for review
HIPAA incidents: 0 | Documentation gaps: 2 | Fall risks addressed: 100% | Restraint reviews: current
Quality Metrics Dashboard
Weekly Review
24h
Readmission rate: 4.2% (target <5%). Patient satisfaction: 4.6/5. Length of stay: 6.2 days (target 7).
AI Council Performance
Monthly Audit
1 week
Recommendation accuracy: 94%. False positive rate: 3.2%. Interventions triggered: 127. Time to alert: avg 48 hrs pre-crisis.
Completed This Week (2)
Incident Report — Resolved
Near-miss medication event
Done
Budget Variance Approved
Q4 overtime allocation
Done
` : ''; // Show gate triggers if any const triggerDisplay = gateTriggers.length > 0 ? `
🟡 ${gateTriggers.join(' + ')}
` : ''; return ` `; } // ============================================ // RENDER MAIN PANEL CARDS - From liveDataset ONLY // ============================================ function renderMainPanel() { const container = document.getElementById("live-pcode-feed"); if (!container) return; // Clear and rebuild from backend truth container.innerHTML = ''; liveDataset.forEach(p => { const card = renderTaskCard(p); container.appendChild(card); }); } function renderTaskCard(p) { const statusUI = mapStatusToUI(p.status); const clockDisplay = formatClockDisplay(p); const progress = p.percent_complete || 0; const isAwaiting = p.status === 'awaiting'; const isBlocked = p.status === 'blocked'; // Domain classification const primaryDomain = p.primaryDomain || p.domain || 'Operations'; const secondaryDomains = p.secondaryDomains || []; const gateTriggers = p.gateTriggers || []; // Only show P-code if it's clean format (P-XXX), otherwise hide completely const isCleanPcode = p.pcode && /^P-\d+/.test(p.pcode); const displayCode = isCleanPcode ? p.pcode : ''; // Build domain tags HTML const domainTagsHtml = `
${primaryDomain} ${secondaryDomains.map(domain => ` ${domain} `).join('')}
${gateTriggers.length > 0 ? `
🟡 ${gateTriggers.join(' + ')}
` : ''} ${isBlocked && p.error ? `
✗ EXECUTION ERROR: ${p.error}
` : ''} `; const card = document.createElement("div"); card.className = `task-card ${statusUI.color} ${isAwaiting ? 'awaiting' : ''} ${isBlocked ? 'blocked' : ''}`; card.id = p.pcode; card.dataset.pcode = p.pcode; card.innerHTML = ` ${isAwaiting ? '' : ''} ${isBlocked ? '' : ''} ${statusUI.label}
${primaryDomain}
${displayCode ? `
${displayCode}
` : ''}
${domainTagsHtml}
${p.assigned_doctor || 'Unassigned'}
${clockDisplay}
${p.origin_request || ''}
`; // Click handler for selection card.style.cursor = 'pointer'; card.addEventListener('click', (e) => { if (!e.target.closest('button')) { selectPcode(p.pcode); if (isAwaiting) { showGovernanceModalFromData(p); } } }); return card; } // ============================================ // SELECTION - Cross-view highlighting // ============================================ function selectPcode(pcodeId) { // Clear all selections document.querySelectorAll('.sidebar-item').forEach(el => el.classList.remove('active')); document.querySelectorAll('.task-card').forEach(el => { el.classList.remove('selected'); el.classList.remove('dimmed'); }); // Highlight sidebar const sidebarItem = document.querySelector(`.sidebar-item[data-pcode="${pcodeId}"]`); if (sidebarItem) { sidebarItem.classList.add('active'); sidebarItem.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } // Highlight card, dim others document.querySelectorAll('.task-card').forEach(card => { if (card.id === pcodeId || card.dataset.pcode === pcodeId) { card.classList.add('selected'); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } else { card.classList.add('dimmed'); } }); } // ============================================ // GOVERNANCE MODAL - With real authorization // Only shows for Compliance, Risk, Security, Strategic/IP, Phoenix // NOT for 404s or execution errors // ============================================ function showGovernanceModalFromData(pcode) { const modal = document.getElementById('governance-modal'); const container = document.getElementById('modal-content'); if (!modal || !container) return; // Domain classification const primaryDomain = pcode.primaryDomain || pcode.domain || 'Operations'; const secondaryDomains = pcode.secondaryDomains || []; const gateTriggers = pcode.gateTriggers || []; const impact = pcode.impact || 'Standard'; // Build explicit trigger reason - shows WHY this needs approval let triggerReason = ''; if (gateTriggers.length > 0) { triggerReason = `Paused due to ${impact} impact + ${gateTriggers.join(' + ')} trigger`; } else if (impact === 'Strategic' || impact === 'Critical') { triggerReason = `Paused due to ${impact} impact classification`; } else { triggerReason = `Paused for Executive Authorization`; } // Build domain routing display const domainRoutingHtml = `
Domain Routing
PRIMARY: ${primaryDomain} ${secondaryDomains.map(domain => ` + ${domain} `).join('')}
${gateTriggers.length > 0 ? `
⚠ GATE TRIGGERS: ${gateTriggers.join(' + ')}
These domains require executive authorization before execution
` : ''}
`; // Build engines locked display (if gate triggers) const enginesLockedHtml = gateTriggers.length > 0 ? `
🔒 ENGINES LOCKED
AI Council, Phoenix, and Worker execution paused pending authorization
` : ''; container.innerHTML = ` ${domainRoutingHtml} ${enginesLockedHtml} `; modal.className = 'governance-modal active'; modal.onclick = (e) => { if (e.target === modal) { leavePaused(); } }; } // ============================================ // AUTHORIZATION - POST to /pcode/issue (VERIFIED LIVE) // "Authorize & Start Execution" button handler // No simulated execution. Server truth only. // ============================================ async function authorizeFromBackend(pcodeId) { console.log('🔐 Authorizing P-code:', pcodeId); // Show loading state const btn = document.querySelector('.btn-primary-action'); if (btn) { btn.disabled = true; btn.textContent = 'Authorizing...'; } // Find the P-code to get its details const pcode = liveDataset.find(p => p.pcode === pcodeId); if (!pcode) { showErrorInModal('P-code not found', 'Could not locate task in dataset.', 'Refresh and retry.'); return; } // VERIFIED PAYLOAD STRUCTURE - matches working /pcode/issue endpoint const payload = { source: "executive-console-authorize", requested_by: "jb", domain_class: pcode.primaryDomain || pcode.domain || 'Operations', urgency_class: "Priority", impact_class: pcode.impact || "Strategic", authorization_class: "Executive", tenant_id: "rni-default-tenant", origin_request: `[AUTHORIZED] ${pcode.origin_request || pcodeId}` }; console.log('📤 POST /pcode/issue (authorize):', payload); try { const response = await fetch(PCODE_ISSUE_ENDPOINT, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); const result = await response.json().catch(() => ({})); // RESPONSE HANDLING: if (result.pcode) { // Success - authorized and new P-code issued console.log('✓ Authorization successful:', result.pcode); showSuccessToast(`Authorized. New P-code: ${result.pcode}`); closeGovernanceModal(); clearSelectionStates(); // Update local state pcode.status = 'active'; pcode.percent_complete = 1; renderSidebar(); renderMainPanel(); // Start polling for progress updates startStatusPolling(result.pcode); } else if (response.status === 404) { // 404 → "Execution service not reachable" (NOT approval) console.error('✗ Execution service not reachable (404)'); showErrorInModal('Execution service not reachable', 'The execution service is not responding. This is a system error, not a governance hold.', 'Fallback mode activated. Manual control enabled.'); activateFallbackMode({ domain: pcode.domain }, 'Authorization service unreachable (404)'); } else if (response.status === 500) { // 500 → Blocked (red) + Fallback console.error('✗ Server error (500):', result); showErrorInModal('Server Error', result.error || 'The server encountered an error processing this request.', 'Fallback mode activated. Manual control enabled.'); pcode.status = 'blocked'; pcode.error = result.error || 'Server error'; renderSidebar(); renderMainPanel(); closeGovernanceModal(); activateFallbackMode({ domain: pcode.domain }, 'Server error (500)'); } else { console.error('✗ ISSUER ERROR:', response.status, result); showErrorInModal('Issuer Error', result.error || 'The issuer returned an error.', 'Manual control available.'); } } catch (error) { // Network failure = service unreachable - ACTIVATE FALLBACK console.error('✗ Network error:', error); showErrorInModal('Network Error', `Could not reach execution service: ${error.message}`, 'Fallback mode activated. Manual control enabled.'); activateFallbackMode({ domain: pcode.domain }, `Authorization network error: ${error.message}`); } finally { // Reset button state if (btn) { btn.disabled = false; btn.textContent = 'Authorize & Start Execution'; } } } // Show error IN the modal (not as separate alert) function showErrorInModal(title, reason, action) { const container = document.getElementById('modal-content'); if (!container) return; // Find or create error display area let errorDiv = container.querySelector('.modal-error'); if (!errorDiv) { errorDiv = document.createElement('div'); errorDiv.className = 'modal-error'; errorDiv.style.cssText = 'margin: 16px 0; padding: 12px; background: #fef2f2; border-radius: 8px; border-left: 4px solid #dc2626;'; container.querySelector('.modal-body').after(errorDiv); } errorDiv.innerHTML = `
✗ ${title}
Reason: ${reason}
Action: ${action}
`; } // ============================================ // MASTER REFRESH - Backend truth overwrites all // Single source of truth. Left column and center mirror SAME record. // ============================================ // ============================================ // REV 65 — PHASE 5 & 6: LIVE BACKEND POLLING // /pcode/recent for activity panel and Phoenix check // ============================================ async function refreshFromBackend() { try { console.log('🔄 Fetching /pcode/recent...'); const response = await fetch(PCODE_RECENT_ENDPOINT); if (response.status === 404) { console.warn('⚠️ /pcode/recent not available (404)'); updatePhoenixStatus('unknown'); return; } if (!response.ok) { console.warn('⚠️ Backend fetch failed:', response.status); updatePhoenixStatus('unknown'); return; } const data = await response.json(); console.log('ISSUER → UI /pcode/recent:', data); // Extract pcodes array from response let rawPcodes = []; if (data && Array.isArray(data.pcodes)) { rawPcodes = data.pcodes; } else if (data && Array.isArray(data)) { rawPcodes = data; } else { console.warn('Unexpected response format:', data); return; } // Take last 5 P-codes for activity panel liveDataset = rawPcodes.slice(0, 5).map(normalizeBackendPcode); console.log(`✅ Loaded ${liveDataset.length} P-codes from backend`); // PHASE 5: Check Phoenix escalation status checkPhoenixEscalationStatus(liveDataset); // Re-render both views renderSidebar(); renderMainPanel(); } catch (error) { console.error('❌ Backend refresh error:', error); updatePhoenixStatus('unknown'); } } // ============================================ // PHASE 5: PHOENIX ESCALATION CHECK // If newest P-code has no orchestrator status after 10s → ESCALATION ACTIVE // ============================================ function checkPhoenixEscalationStatus(pcodes) { if (!pcodes || pcodes.length === 0) { updatePhoenixStatus('idle'); return; } const newest = pcodes[0]; const now = new Date(); const issuedAt = new Date(newest.started_at || newest.created_at || now); const ageMs = now - issuedAt; // If newest P-code is less than 10s old and has no orchestrator status if (ageMs < PHOENIX_CHECK_DELAY && !newest.orchestrator_status) { // Still waiting - check again later console.log('⏳ Phoenix check: P-code too new, waiting...'); updatePhoenixStatus('watching'); return; } // If older than 10s and still no orchestrator status → ESCALATION if (ageMs >= PHOENIX_CHECK_DELAY && !newest.orchestrator_status) { console.warn('🔄 AUTOMATED RECOVERY ACTIVE - No orchestrator status'); updatePhoenixStatus('escalation'); return; } // Has orchestrator status → healthy console.log('✅ Phoenix check: Orchestrator healthy'); updatePhoenixStatus('healthy'); } // ============================================ // PHOENIX STATUS UI UPDATE // ============================================ function updatePhoenixStatus(status) { phoenixStatus = status; console.log('PHOENIX STATUS:', phoenixStatus); const phoenixNode = document.querySelector('.pipeline-node.node-blue'); if (!phoenixNode) return; const statusEl = phoenixNode.querySelector('.pipeline-node-status'); if (!statusEl) return; // Executive-grade status labels with color chips switch(status) { case 'escalation': // Recovering - amber, brief state statusEl.innerHTML = '🔄 Fully Self-Healing...'; statusEl.style.color = '#f59e0b'; phoenixNode.style.animation = 'subtle-pulse 2s ease-in-out infinite'; showRecoveryBanner(); break; case 'watching': statusEl.innerHTML = '🔄 Fully Self-Healing...'; statusEl.style.color = '#f59e0b'; phoenixNode.style.animation = ''; break; case 'healthy': statusEl.innerHTML = ' Fully Self-Healed'; statusEl.style.color = '#10b981'; phoenixNode.style.animation = ''; hideRecoveryBanner(); break; case 'idle': statusEl.innerHTML = ' Stable'; statusEl.style.color = '#10b981'; phoenixNode.style.animation = ''; hideRecoveryBanner(); break; default: statusEl.innerHTML = ' Stable'; statusEl.style.color = '#10b981'; phoenixNode.style.animation = ''; } } // ============================================ // AUTOMATED RECOVERY BANNER // Executive-grade messaging, Phoenix lives in tooltip only // ============================================ function showRecoveryBanner() { // Remove existing banner if any hideRecoveryBanner(); const banner = document.createElement('div'); banner.id = 'recovery-banner'; banner.style.cssText = ` position: fixed; top: 0; left: 0; right: 0; background: linear-gradient(90deg, #f59e0b, #d97706); color: white; padding: 12px 20px; text-align: center; z-index: 10001; box-shadow: 0 2px 8px rgba(0,0,0,0.2); `; banner.innerHTML = `
🔄 Fully Self-Healing
System handling automatically. No action required.
`; document.body.prepend(banner); } function hideRecoveryBanner() { const existing = document.getElementById('recovery-banner'); if (existing) existing.remove(); } // Start periodic refresh setInterval(refreshFromBackend, RECENT_REFRESH_INTERVAL); // ============================================ // REV 62 — STATUS POLLING REMOVED // No orchestrator calls. No /pcode/status polling. // P-codes display from successful issue responses only. // ============================================ function startStatusPolling(pcodeId) { // REMOVED: No status polling console.log(`📋 P-code ${pcodeId} added to local session`); } function stopStatusPolling(pcodeId) { // REMOVED: No status polling } // ============================================ // FILE UPLOAD HANDLER // ============================================ let uploadedFiles = []; function handleFileUpload(files) { if (!files || files.length === 0) return; const maxFiles = 5; const maxSizeMB = 10; Array.from(files).forEach(file => { if (uploadedFiles.length >= maxFiles) { showErrorToast(`Maximum ${maxFiles} files allowed`); return; } if (file.size > maxSizeMB * 1024 * 1024) { showErrorToast(`${file.name} exceeds ${maxSizeMB}MB limit`); return; } uploadedFiles.push(file); console.log('📎 File attached:', file.name); }); updateAttachedFilesDisplay(); showSuccessToast(`${files.length} file(s) attached`); document.getElementById('file-upload-input').value = ''; } function updateAttachedFilesDisplay() { let container = document.getElementById('attached-files-display'); const requestBox = document.querySelector('.request-box'); const actionsDiv = requestBox.querySelector('.request-actions'); if (!container && uploadedFiles.length > 0) { container = document.createElement('div'); container.id = 'attached-files-display'; container.style.cssText = 'margin-bottom: 12px; display: flex; flex-wrap: wrap; gap: 6px;'; requestBox.insertBefore(container, actionsDiv); } if (container) { if (uploadedFiles.length === 0) { container.remove(); return; } container.innerHTML = uploadedFiles.map((file, i) => `
${file.name}
`).join(''); } } function removeUploadedFile(index) { uploadedFiles.splice(index, 1); updateAttachedFilesDisplay(); } function clearUploadedFiles() { uploadedFiles = []; const container = document.getElementById('attached-files-display'); if (container) container.remove(); } // ============================================ // DOWNLOAD OPERATIONS REPORT (PDF) // ============================================ function downloadOperationsReport() { const { jsPDF } = window.jspdf; const doc = new jsPDF(); const now = new Date(); const timestamp = now.toISOString().slice(0, 10); // Colors const rniGreen = [67, 219, 163]; const darkGray = [31, 41, 55]; const mutedGray = [107, 114, 128]; // Header doc.setFillColor(...rniGreen); doc.rect(0, 0, 210, 35, 'F'); doc.setTextColor(255, 255, 255); doc.setFontSize(24); doc.setFont('helvetica', 'bold'); doc.text('RNI Clinical Console', 20, 20); doc.setFontSize(11); doc.setFont('helvetica', 'normal'); doc.text('Operations Report', 20, 28); doc.setFontSize(10); doc.text(now.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }), 140, 20); // System Status let y = 50; doc.setTextColor(...darkGray); doc.setFontSize(14); doc.setFont('helvetica', 'bold'); doc.text('System Status', 20, y); y += 10; doc.setFontSize(11); doc.setFont('helvetica', 'normal'); const statusData = [ ['Operations', '24 / 160'], ['Uptime', '99.94%'], ['Council', '6 doctors online'], ['Workers', '10/10 healthy'], ['Phoenix', 'Stable'] ]; statusData.forEach(([label, value]) => { doc.setTextColor(...mutedGray); doc.text(label + ':', 20, y); doc.setTextColor(...darkGray); doc.setFont('helvetica', 'bold'); doc.text(value, 60, y); doc.setFont('helvetica', 'normal'); y += 7; }); // Active P-Codes y += 10; doc.setTextColor(...darkGray); doc.setFontSize(14); doc.setFont('helvetica', 'bold'); doc.text('Active P-Codes', 20, y); y += 10; doc.setFontSize(10); if (liveDataset && liveDataset.length > 0) { liveDataset.forEach((p, i) => { if (y > 260) { doc.addPage(); y = 20; } doc.setFont('helvetica', 'bold'); doc.setTextColor(...rniGreen); doc.text(`${i + 1}. ${p.pcode || 'P-XXX'}`, 20, y); y += 6; doc.setFont('helvetica', 'normal'); doc.setTextColor(...mutedGray); doc.text(`Domain: ${p.domain || 'Unclassified'} | Status: ${p.status || 'Unknown'}`, 25, y); y += 8; }); } else { doc.setTextColor(...mutedGray); doc.text('No active P-codes in current session.', 20, y); } // Footer const pageHeight = doc.internal.pageSize.height; doc.setFillColor(...rniGreen); doc.rect(0, pageHeight - 15, 210, 15, 'F'); doc.setTextColor(255, 255, 255); doc.setFontSize(9); doc.text('Recovery Network Inc. — data that heals™', 20, pageHeight - 6); doc.text('CONFIDENTIAL', 170, pageHeight - 6); doc.save(`RNI-Operations-Report-${timestamp}.pdf`); showSuccessToast('PDF downloaded'); } // ============================================ // ERROR TOAST - Service unreachable messages // ============================================ function showErrorToast(message) { const existing = document.querySelector('.error-toast'); if (existing) existing.remove(); const toast = document.createElement('div'); toast.className = 'error-toast'; toast.style.cssText = ` position: fixed; bottom: 20px; right: 20px; background: #fef2f2; color: #991b1b; padding: 12px 20px; border-radius: 8px; box-shadow: 0 4px 12px rgba(220, 38, 38, 0.2); border-left: 4px solid #dc2626; z-index: 9999; font-size: 14px; font-weight: 500; animation: toastSlideIn 300ms ease-out; `; toast.innerHTML = `${message}`; document.body.appendChild(toast); setTimeout(() => { toast.style.animation = 'toastSlideIn 300ms ease-out reverse'; setTimeout(() => toast.remove(), 300); }, 6000); } // ============================================ // CARD ACTION HANDLER // ============================================ function handleCardAction(pcodeId) { const pcode = liveDataset.find(p => p.pcode === pcodeId); if (!pcode) return; if (pcode.status === 'awaiting') { showGovernanceModalFromData(pcode); } else { // Show detail view for non-awaiting P-codes showSimpleDetail(pcode); } } // ============================================ // INITIALIZATION - Wire to backend // No client-side execution paths // UI is a control panel only, not a simulator // ============================================ document.addEventListener('DOMContentLoaded', () => { // Create live feed container if not exists const mainScroll = document.querySelector('.main-scroll'); if (mainScroll && !document.getElementById('live-pcode-feed')) { const feedContainer = document.createElement('div'); feedContainer.id = 'live-pcode-feed'; feedContainer.className = 'task-section'; // Insert after the request box const requestBox = document.querySelector('.request-box'); if (requestBox) { requestBox.after(feedContainer); } else { mainScroll.appendChild(feedContainer); } } // Initial render renderSidebar(); renderMainPanel(); // PHASE 6: Load recent P-codes from backend console.log('🚀 Loading recent P-codes from backend...'); refreshFromBackend(); console.log('✓ Rev 71 initialized - FULL HANDSHAKE WIRING'); }); // ============================================ // REV 65 — PHASE 7: CONSOLE LOGGING // Full visibility into UI ↔ Backend handshake // ============================================ console.log('========================================'); console.log('🏥 RNI Clinical Console Rev 15'); console.log('========================================'); console.log('📡 POST /pcode/issue — Submit new P-code'); console.log('📡 GET /pcode/recent — Load activity panel'); console.log('📡 GET /health — Service health check'); console.log('🔥 Phoenix escalation: Data-driven'); console.log('========================================'); // P-code drill-down modal function openPcodeDetail(pcode, title, doctor, status, description) { const modal = document.createElement('div'); modal.style.cssText = ` position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.6); display: flex; align-items: center; justify-content: center; z-index: 10000; animation: fadeIn 0.2s; `; modal.innerHTML = `

${title}

${pcode}
Assigned Doctor
${doctor}
Status
${status}
Description
${description}
Timeline
Started: Nov 18, 2025
⦿
In Progress: 2 days elapsed
Due: Nov 22, 2025 (2 days remaining)
Council Recommendations
Dr. Olivia: Prioritize user feedback integration before final testing.

Dr. Williams: Ensure API response time stays under 200ms threshold.

Dr. Taylor: Add Phoenix monitoring hooks for real-time error detection.
`; document.body.appendChild(modal); // Close on background click modal.addEventListener('click', (e) => { if (e.target === modal) modal.remove(); }); } // Add click handlers to all task cards document.querySelectorAll('.task-card').forEach(card => { card.style.cursor = 'pointer'; card.addEventListener('click', function(e) { // Don't trigger if clicking a button if (e.target.closest('button')) return; const title = this.querySelector('.task-title').textContent; const pcode = this.querySelector('.task-code').textContent; const doctor = this.querySelector('.task-meta-item:first-child span').textContent; const status = this.querySelector('.task-meta-item:nth-child(2) span').textContent; const description = this.querySelector('.task-description, .task-list')?.textContent || 'No description available'; openPcodeDetail(pcode, title, doctor, status, description); }); }); // Add CSS animations const style = document.createElement('style'); style.textContent = ` @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } `; document.head.appendChild(style); /* ================================ REV 52 - Legacy functions kept for compatibility All real logic now in telemetry system above ================================ */ /* Show Governance Modal - delegates to new system */function showGovernanceModal(pcode) { // Convert old format to new format and delegate const normalizedPcode = { pcode: pcode.pcode || pcode.id, status: 'awaiting', domain: pcode.domain_class || pcode.domain || 'System', impact: pcode.impact_class || 'Standard', origin_request: pcode.origin_request || '', assigned_doctor: pcode.requested_by || 'Executive' }; showGovernanceModalFromData(normalizedPcode); } /* Legacy authorize function - delegates to new backend call */function authorizeAndStart(pcodeId) { authorizeFromBackend(pcodeId); } /* Handle awaiting click - delegates to new system */function handleAwaitingClick(pcodeId, pcodeData) { selectPcode(pcodeId); showGovernanceModal(pcodeData); } /* Success Toast */function showSuccessToast(message) { const toast = document.createElement('div'); toast.className = 'success-toast'; toast.innerHTML = `
Success
${message}
`; document.body.appendChild(toast); setTimeout(() => { toast.style.animation = 'toastSlideIn 300ms ease-out reverse'; setTimeout(() => toast.remove(), 300); }, 4000); } // ============================================ // NOTES - Governance Artifacts (NOT social chatter) // "Add Comment / Modify" only appends a note // It does NOT resubmit or reroute // ============================================ function addNoteModify(id) { console.log("📝 Adding note to:", id); const noteText = prompt(`Add note for P-Code ${id}:\n\nThis appends a governance note to the audit trail.\nIt does NOT resubmit or reroute the task.`); if (noteText && noteText.trim()) { // Just log the note - no resubmission, no rerouting console.log(`✏️ Note appended to ${id}:`, noteText); showSuccessToast(`Note added to P-Code ${id}. Audit trail updated.`); closeGovernanceModal(); } } // Legacy alias function addCommentModify(id) { addNoteModify(id); } function leavePaused() { console.log("⏸ Left paused - no action taken"); closeGovernanceModal(); clearSelectionStates(); } function closeGovernanceModal() { const modal = document.getElementById('governance-modal'); if (modal) { modal.className = 'governance-modal'; } } function clearSelectionStates() { document.querySelectorAll('.sidebar-item').forEach(item => { item.classList.remove('selected', 'active'); }); document.querySelectorAll('.task-card').forEach(card => { card.classList.remove('selected', 'dimmed'); }); } /* Simple detail pane for non-awaiting P-codes */function showSimpleDetail(pcode) { const pane = document.getElementById("pcode-detail-pane"); if (!pane) return; const statusUI = mapStatusToUI(pcode.status || 'active'); // Use request snippet as title (first 60 chars), P-code as subtitle const requestSnippet = pcode.origin_request ? (pcode.origin_request.length > 60 ? pcode.origin_request.substring(0, 60) + '...' : pcode.origin_request) : 'Request Details'; const shortPcode = pcode.pcode ? `P-${pcode.pcode.substring(0, 8)}...` : ''; pane.className = "active"; pane.innerHTML = `

${requestSnippet}

${shortPcode} • ${statusUI.label}
Domain: ${pcode.domain || "—"} Impact: ${pcode.impact || "—"} Assigned: ${pcode.assigned_doctor || "—"} Progress: ${pcode.percent_complete || 0}%
Full Request:
${pcode.origin_request || "—"}
`; pane.scrollIntoView({ behavior: 'smooth', block: 'start' }); } /* Legacy show detail - delegates to new system */function showPcodeDetail(pcode) { const normalizedPcode = { pcode: pcode.pcode || pcode.id, status: pcode.status || 'active', domain: pcode.domain_class || pcode.domain || 'System', impact: pcode.impact_class || pcode.impact || 'Standard', origin_request: pcode.origin_request || '', assigned_doctor: pcode.requested_by || pcode.assigned_doctor || 'Unassigned', percent_complete: pcode.percent_complete || 0 }; if (normalizedPcode.status === 'awaiting' || pcode.impact_class === 'Strategic' || pcode.impact_class === 'Critical') { normalizedPcode.status = 'awaiting'; showGovernanceModalFromData(normalizedPcode); } else { showSimpleDetail(normalizedPcode); } } function closeDetail() { const pane = document.getElementById("pcode-detail-pane"); if (pane) pane.className = ""; } // ============================================ // CLINICAL CONSOLE - ROLE SWITCHING // ============================================ const roleNames = { floor_nurse: 'Floor Nurse', physician: 'Physician', charge_nurse: 'Charge Nurse', case_manager: 'Case Manager', supervisor: 'Supervisor' }; function switchRole(role) { console.log('🔄 Switching to role:', roleNames[role] || role); // Hide all role views (main content) document.querySelectorAll('.role-view').forEach(view => { view.classList.remove('active'); view.style.display = 'none'; }); // Show selected role view const selectedView = document.getElementById(`view-${role}`); if (selectedView) { selectedView.style.display = 'block'; selectedView.classList.add('active'); } // Hide all sidebar role views document.querySelectorAll('.sidebar-role-view').forEach(view => { view.classList.remove('active'); view.style.display = 'none'; }); // Show selected sidebar role view const selectedSidebar = document.getElementById(`sidebar-${role}`); if (selectedSidebar) { selectedSidebar.style.display = 'block'; selectedSidebar.classList.add('active'); } // Update role chip in Ask Council const roleChip = document.getElementById('pill-role'); if (roleChip) { roleChip.textContent = roleNames[role] || role; } // Count tasks in the active view const activeView = document.querySelector('.role-view.active'); const urgentTasks = activeView ? activeView.querySelectorAll('.task-card.red, .task-card.yellow').length : 0; // Update Active count in sidebar const activeCountEl = document.querySelector('.sidebar-stat-value.red'); if (activeCountEl) { activeCountEl.textContent = urgentTasks; } // Show toast showToast(`Switched to ${roleNames[role]} view`, 'success'); } // Shift Clock Countdown function updateShiftClock() { const clock = document.getElementById('shiftClock'); if (!clock) return; let [h, m, s] = clock.textContent.split(':').map(Number); if (s > 0) s--; else if (m > 0) { m--; s = 59; } else if (h > 0) { h--; m = 59; s = 59; } clock.textContent = `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`; } setInterval(updateShiftClock, 1000); // Toast notification function showToast(message, type = 'info') { // Remove existing toasts document.querySelectorAll('.rni-toast').forEach(t => t.remove()); const toast = document.createElement('div'); toast.className = `rni-toast ${type}`; // Elegant center notification for role switches if (message.includes('Switched to')) { const roleName = message.replace('Switched to ', '').replace(' view', ''); toast.innerHTML = `
Now viewing as
${roleName}
`; toast.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.9); padding: 32px 48px; background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border-radius: 16px; box-shadow: 0 24px 80px rgba(0, 0, 0, 0.12), 0 0 1px rgba(0, 0, 0, 0.1); z-index: 10000; text-align: center; opacity: 0; transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1), transform 0.6s cubic-bezier(0.16, 1, 0.3, 1); `; // Add inner styles const style = document.createElement('style'); style.textContent = ` .role-toast-label { font-size: 11px; text-transform: uppercase; letter-spacing: 2px; color: #9CA3AF; margin-bottom: 8px; font-weight: 500; } .role-toast-name { font-size: 24px; font-weight: 600; color: #111827; margin-bottom: 16px; } .role-toast-bar { width: 0%; height: 3px; background: linear-gradient(90deg, #4D7CFF, #7C9FFF); border-radius: 2px; margin: 0 auto; animation: roleBarFill 2s cubic-bezier(0.16, 1, 0.3, 1) forwards; animation-delay: 0.3s; } @keyframes roleBarFill { 0% { width: 0%; opacity: 0; } 10% { opacity: 1; } 100% { width: 100%; opacity: 1; } } `; document.head.appendChild(style); document.body.appendChild(toast); // Animate in requestAnimationFrame(() => { toast.style.opacity = '1'; toast.style.transform = 'translate(-50%, -50%) scale(1)'; }); // Animate out setTimeout(() => { toast.style.opacity = '0'; toast.style.transform = 'translate(-50%, -50%) scale(0.95)'; setTimeout(() => { toast.remove(); style.remove(); }, 600); }, 2200); } else { // Standard toast for other messages toast.innerHTML = ` ${message}`; toast.style.cssText = ` position: fixed; bottom: 24px; right: 24px; padding: 14px 20px; background: ${type === 'success' ? '#4D7CFF' : '#3B82F6'}; color: white; border-radius: 8px; font-size: 14px; font-weight: 500; z-index: 10000; display: flex; align-items: center; gap: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); animation: slideIn 0.3s ease-out; `; document.body.appendChild(toast); setTimeout(() => { toast.style.animation = 'slideIn 0.3s ease-out reverse'; setTimeout(() => toast.remove(), 300); }, 3000); } } // Quick Ask presets function quickAsk(type) { const input = document.getElementById('request-input'); const box = document.getElementById('askCouncilBox'); const presets = { 'attention': 'Which patients need immediate attention right now?', 'hrv': 'What is the current HRV status across all monitored patients?', 'discharge': 'Which patients are ready for discharge or step-down?', 'handoffs': 'What are the pending handoffs for this shift?' }; // Expand the Ask Council box if collapsed if (box && box.classList.contains('collapsed')) { box.classList.remove('collapsed'); } if (input && presets[type]) { input.value = presets[type]; input.focus(); } } // Dark Mode Toggle // Toggle Ask Council Box function toggleAskCouncil() { const box = document.getElementById('askCouncilBox'); const icon = document.getElementById('askToggleIcon'); box.classList.toggle('collapsed'); } function toggleDarkMode() { document.body.classList.toggle('dark-mode'); const icon = document.getElementById('darkModeIcon'); if (document.body.classList.contains('dark-mode')) { icon.classList.remove('fa-moon'); icon.classList.add('fa-sun'); showToast('Dark mode enabled', 'success'); } else { icon.classList.remove('fa-sun'); icon.classList.add('fa-moon'); showToast('Light mode enabled', 'success'); } } // S.O.A.P. Auto-Draft Viewer function viewSOAPDraft(patientId) { const drafts = { 'james-wilson': { patient: 'James Wilson', date: new Date().toLocaleDateString(), subjective: 'Patient reports improved mood, sleeping 7 hours/night, appetite returned. Denies SI/HI. States "feeling more like myself." Engaged in group therapy.', objective: 'Alert, oriented x4. Affect euthymic, congruent. Speech normal rate/rhythm. No psychomotor changes. VS: HR 72, BP 118/76, SpO2 99%.', assessment: 'Generalized Anxiety Disorder, improving. PHQ-9: 8 (↓4 from admission). GAD-7: 6 (↓5). Sleep improved. Medication adherence 100%.', plan: '1. Continue current medication regimen\n2. Continue group therapy daily\n3. Family session scheduled Thursday\n4. Target discharge Day 7 pending stability' } }; const draft = drafts[patientId]; if (!draft) { showToast('Draft not found', 'error'); return; } // Create modal with S.O.A.P. content const modal = document.createElement('div'); modal.className = 'soap-modal'; modal.innerHTML = `

S.O.A.P. Auto-Draft

${draft.patient} • ${draft.date} • Generated by Dr. Williams

S Subjective
${draft.subjective}
O Objective
${draft.objective}
A Assessment
${draft.assessment}
P Plan
${draft.plan}
`; document.body.appendChild(modal); } console.log('🏥 RNI Clinical Console Rev 24 - Role-Specific Views'); console.log('═══════════════════════════════════════════════════'); console.log('+ 17/17 Clinical Grievances Addressed'); console.log('+ EHR Sync Badge (Epic: Connected)'); console.log('+ S.O.A.P. Auto-Draft Viewer'); console.log('+ Shift Handoff Summary Card'); console.log('+ Med Reconciliation Task'); console.log('+ Dark Mode Toggle'); console.log('+ 5 Role Views with Task Filtering'); console.log('═══════════════════════════════════════════════════');