// Core UI & Modal Elements const modal = document.getElementById("consultationModal"); const addMedBtn = document.getElementById("addMed"); const medList = document.getElementById("medicineList"); const sendRxBtn = document.getElementById("sendRx"); const closeModal = document.querySelector(".close-modal"); const startRecordBtn = document.getElementById("startRecording"); const recordingStatus = document.getElementById("recordingStatus"); const aiInsightsBox = document.getElementById("aiInsights"); const insightText = document.getElementById("insightText"); const queueDateInput = document.getElementById("queueDate"); const newWalkinBtn = document.getElementById("newWalkinBtn"); const labList = document.getElementById("labTestList"); const addLabBtn = document.getElementById("addLabTest"); // 1. App State & Stores let isScribing = false; let currentPatientId = "#012"; let recognition; let mediaRecorder; let audioChunks = []; const patientDataStore = { "#012": { notes: "", summary: "" }, "#013": { notes: "", summary: "" }, "#014": { notes: "", summary: "" } }; const SECTION_META = { overview: { target: 'overview-section', title: 'Clinic Overview', subtitle: 'Live queue, stats, and AI insights for today.' }, queue: { target: 'overview-section', title: 'Live Queue', subtitle: 'Patients waiting and in consultation.' }, patients: { target: 'patients-section', title: 'Patient Records', subtitle: 'Search history, visits, and contact details.' }, pharmacy: { target: 'pharmacy-section', title: 'Pharmacy', subtitle: 'Inventory, prescriptions, and stock alerts.' }, lab: { target: 'lab-section', title: 'Laboratory', subtitle: 'Orders, sample collection, and results.' }, zen: { target: 'doctor-zen-section', title: 'Clinical Workspace', subtitle: 'Document visits, prescribe, and review vitals.' } }; const ROLE_CONFIG = { DOCTOR: { hideSections: ['overview', 'billing', 'staff'], defaultSection: 'zen', displayName: 'Dr. Sharma' }, OWNER: { hideSections: [], defaultSection: 'overview', displayName: null }, RECEPTIONIST: { hideSections: ['pharmacy', 'lab'], defaultSection: 'queue', displayName: 'Reception' } }; function getUserRole() { return localStorage.getItem('userRole') || 'OWNER'; } function resolveSectionTarget(sectionId) { const role = getUserRole(); const config = ROLE_CONFIG[role] || ROLE_CONFIG.OWNER; if (sectionId === 'queue' && role === 'DOCTOR') return 'doctor-zen-section'; if (sectionId === 'zen') return 'doctor-zen-section'; const meta = SECTION_META[sectionId]; return meta ? meta.target : 'overview-section'; } function updateSectionPageHeader(sectionId) { const header = document.getElementById('section-page-header'); const titleEl = document.getElementById('sectionPageTitle'); const subtitleEl = document.getElementById('sectionPageSubtitle'); if (!header || !titleEl || !subtitleEl) return; const isDoctor = getUserRole() === 'DOCTOR'; const isClinicalView = sectionId === 'zen' || sectionId === 'queue'; const meta = SECTION_META[sectionId]; if (isDoctor && !isClinicalView && meta) { titleEl.textContent = meta.title; subtitleEl.textContent = meta.subtitle; header.classList.remove('hidden'); } else { header.classList.add('hidden'); } } function setActiveNavLink(sectionId) { const isDoctor = getUserRole() === 'DOCTOR'; const activeKey = (sectionId === 'zen' || (sectionId === 'queue' && isDoctor)) ? 'queue' : sectionId; document.querySelectorAll('.side-nav a[data-section]').forEach(link => { link.classList.toggle('active', link.dataset.section === activeKey); }); } function applyRoleNav() { const role = getUserRole(); const config = ROLE_CONFIG[role] || ROLE_CONFIG.OWNER; document.querySelectorAll('.side-nav a[data-section]').forEach(link => { const hidden = config.hideSections.includes(link.dataset.section); link.style.display = hidden ? 'none' : ''; }); } // 2. Initialization & Speech Recognition Setup document.addEventListener("DOMContentLoaded", () => { const userRole = getUserRole(); const userEmail = localStorage.getItem('userEmail') || 'admin@curio.app'; const config = ROLE_CONFIG[userRole] || ROLE_CONFIG.OWNER; const roleDisplay = document.querySelector(".user-profile .info strong"); const emailDisplay = document.querySelector(".user-profile .info span"); if (roleDisplay) { roleDisplay.innerText = config.displayName || (userRole.charAt(0) + userRole.slice(1).toLowerCase()); } if (emailDisplay) emailDisplay.innerText = userEmail; if (userRole === 'DOCTOR') { document.body.classList.add('role-doctor'); } applyRoleNav(); document.getElementById('sideNav')?.addEventListener('click', (e) => { const link = e.target.closest('a[data-section]'); if (!link || link.hasAttribute('data-external')) return; e.preventDefault(); showSection(link.dataset.section); }); showSection(config.defaultSection === 'zen' ? 'zen' : config.defaultSection); // AI Nudge Simulation Logic const notesArea = document.getElementById("consultationNotes"); const nudgeText = document.getElementById("aiNudgeText"); const tagsContainer = document.querySelector(".suggested-tags"); if (notesArea) { notesArea.addEventListener("input", (e) => { const val = e.target.value.toLowerCase(); if (val.includes("fever") || val.includes("temperature")) { nudgeText.innerText = "✨ AI suggests: Patient has elevated temp. Consider prescribing Paracetamol and checking for throat infection."; tagsContainer.innerHTML = '#ViralFever#InfectionCheck'; } else if (val.includes("cough") || val.includes("breath")) { nudgeText.innerText = "✨ AI suggests: Respiratory symptoms detected. Check SpO2 and listen for chest congestion."; tagsContainer.innerHTML = '#AsthmaProtocol#Bronchitis'; } }); } // Initialize Recognition if ('webkitSpeechRecognition' in window) { recognition = new webkitSpeechRecognition(); recognition.continuous = true; recognition.interimResults = true; recognition.maxAlternatives = 3; recognition.onresult = (event) => { for (let i = event.resultIndex; i < event.results.length; ++i) { if (event.results[i].isFinal) { const transcript = event.results[i][0].transcript; document.getElementById("consultationNotes").value += transcript + '. '; } } }; recognition.onerror = () => { isScribing = false; updateScribeUI(); }; } }); // 3. Section Switching Logic window.showSection = (sectionId) => { const sections = ['overview-section', 'patients-section', 'pharmacy-section', 'lab-section', 'doctor-zen-section']; sections.forEach(id => { const el = document.getElementById(id); if (el) el.classList.add('hidden'); }); const target = resolveSectionTarget(sectionId); const targetEl = document.getElementById(target); if (targetEl) targetEl.classList.remove('hidden'); if (sectionId === 'queue' && target === 'overview-section') { document.getElementById('queue-section')?.scrollIntoView({ behavior: 'smooth', block: 'start' }); } const headerSection = (sectionId === 'queue' && getUserRole() === 'DOCTOR') ? 'zen' : sectionId; updateSectionPageHeader(headerSection); setActiveNavLink(sectionId); if (window.innerWidth <= 768) { document.getElementById('sidebar')?.classList.remove('open'); } return false; }; // 4. Clinical Context & Scribe Logic window.toggleZenScribe = async () => { if (!recognition) { alert("Speech Recognition not supported."); return; } isScribing = !isScribing; updateScribeUI(); if (isScribing) { recognition.lang = document.getElementById("scribeLang")?.value || 'en-US'; recognition.start(); startDeepCapture(); } else { recognition.stop(); if (mediaRecorder) mediaRecorder.stop(); } }; function updateScribeUI() { const btn = document.getElementById("zenScribeBtn"); const status = document.getElementById("scribeStatus"); if (!btn || !status) return; if (isScribing) { btn.innerHTML = "🛑 Stop Scribe"; btn.style.background = "#EF4444"; btn.style.color = "white"; status.classList.remove("hidden"); } else { btn.innerHTML = "🎙️ Scribe"; btn.style.background = ""; // Resets to CSS default btn.style.color = ""; status.classList.add("hidden"); } } async function startDeepCapture() { try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); mediaRecorder = new MediaRecorder(stream); audioChunks = []; mediaRecorder.ondataavailable = (e) => audioChunks.push(e.data); mediaRecorder.onstop = () => { const blob = new Blob(audioChunks, { type: 'audio/wav' }); processWithWhisper(blob); }; mediaRecorder.start(); } catch (err) { console.warn("Mic access denied for Deep Scribe"); } } async function processWithWhisper(blob) { const formData = new FormData(); formData.append("file", blob, "audio.wav"); formData.append("model", "tiny"); // Explicitly tell the server which model to use try { const res = await fetch("https://curio.applaude.net/api/whisper/v1/audio/transcriptions", { method: "POST", body: formData }); const data = await res.json(); if (data.text) { document.getElementById("consultationNotes").value += "\n[DEEP SCRIBE]: " + data.text; generateSummary(true); } } catch (e) { console.warn("Deep Scribe error, using fallback summary.", e); generateSummary(document.getElementById("scribeLang")?.value === 'te-IN'); } } function generateSummary(isTelugu = false) { const notes = document.getElementById("consultationNotes").value; if (!notes) return; const summary = isTelugu ? "📝 [TRANSLATED] CLINICAL SUMMARY: Patient presents in Telugu. Dry cough and fatigue noted. Recommended fluids and rest." : "📋 CLINICAL SUMMARY: Patient presents with persistent dry cough. Recommended hydration and follow-up."; document.getElementById("summaryText").innerText = summary; document.getElementById("aiSummaryCard").classList.remove("hidden"); patientDataStore[currentPatientId] = { notes, summary }; } window.switchPatientContext = (name, token, triage) => { if (currentPatientId) patientDataStore[currentPatientId].notes = document.getElementById("consultationNotes").value; isScribing = false; updateScribeUI(); currentPatientId = token; const data = patientDataStore[token] || { notes: "", summary: "" }; document.getElementById("consultationNotes").value = data.notes; document.getElementById("summaryText").innerText = data.summary; if (data.summary) document.getElementById("aiSummaryCard").classList.remove("hidden"); else document.getElementById("aiSummaryCard").classList.add("hidden"); const patientHeading = document.querySelector(".patient-identity h1"); if (patientHeading) patientHeading.innerHTML = `${name} (32y, Female)`; const metaPills = document.querySelectorAll(".patient-identity .meta-pills"); if (metaPills[1]) { metaPills[1].innerHTML = ` ${token} ${triage} `; } }; // 5. Global Helpers & Modal Handlers window.openHistory = () => { const heading = document.querySelector(".patient-identity h1"); const name = heading ? heading.innerText.split(' (')[0] : 'Patient'; alert(`📂 Loading History for ${name}...\n\n- Visit (05/12/26): Chronic Gastritis`); }; window.openConsultation = () => { const triagePills = document.querySelectorAll(".patient-identity .meta-pills .pill.time"); const triage = triagePills[triagePills.length - 1]; const rxField = document.getElementById("rxDiagnosis"); if (rxField && triage) rxField.value = triage.innerText; if (modal) modal.classList.add('open'); }; window.shareSummary = () => alert("📤 Summary sent to Patient's WhatsApp."); window.printSummary = () => alert("🖨️ Printing Handover Note..."); window.toggleSidebar = () => { document.getElementById('sidebar')?.classList.toggle('open'); }; // Global Listeners if (closeModal) closeModal.onclick = () => modal.classList.remove('open'); window.onclick = (e) => { if (e.target == modal) modal.classList.remove('open'); };