curaflow/dashboard.js

200 lines
8.1 KiB
JavaScript

// 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: "" }
};
// 2. Initialization & Speech Recognition Setup
document.addEventListener("DOMContentLoaded", () => {
const userRole = localStorage.getItem('userRole') || 'OWNER';
const userEmail = localStorage.getItem('userEmail') || 'admin@curio.app';
// Set Sidebar Profile
const roleDisplay = document.querySelector(".user-profile .info strong");
const emailDisplay = document.querySelector(".user-profile .info span");
if (roleDisplay) roleDisplay.innerText = userRole.charAt(0) + userRole.slice(1).toLowerCase();
if (emailDisplay) emailDisplay.innerText = userEmail;
// Apply Role-Based Filtering
if (userRole === 'DOCTOR') {
document.querySelectorAll('.side-nav a').forEach(link => {
const text = link.innerText;
if (text.includes('Billing') || text.includes('Staff') || text.includes('Overview')) {
link.style.display = 'none';
}
});
showSection('zen');
} else {
showSection('overview');
}
// 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 = (sectionId === 'zen' || (sectionId === 'queue' && localStorage.getItem('userRole') === 'DOCTOR'))
? 'doctor-zen-section'
: (sectionId === 'patients' ? 'patients-section'
: (sectionId === 'pharmacy' ? 'pharmacy-section'
: (sectionId === 'lab' ? 'lab-section' : 'overview-section')));
const targetEl = document.getElementById(target);
if (targetEl) targetEl.classList.remove('hidden');
document.querySelectorAll('.side-nav a').forEach(link => {
link.classList.remove('active');
if (link.innerText.toLowerCase().includes(sectionId)) link.classList.add('active');
});
};
// 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 (isScribing) {
btn.innerText = "🛑 Stop AI Scribe";
btn.style.background = "#EF4444";
status.classList.remove("hidden");
} else {
btn.innerText = "🎙️ Start AI Scribe";
btn.style.background = "";
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");
try {
const res = await fetch("https://curio.applaude.net/api/whisper/v1/transcribe", { 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) { 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");
document.querySelector(".current-patient h1").innerHTML = `${name} <small>(32y, Female)</small>`;
document.querySelector(".patient-meta").innerHTML = `<span>${token}</span> • <span>${triage}</span> • <span class="visit-timer">00:00</span>`;
};
// 5. Global Helpers & Modal Handlers
window.openHistory = () => {
const name = document.querySelector(".current-patient h1").innerText.split(' (')[0];
alert(`📂 Loading History for ${name}...\n\n- Visit (05/12/26): Chronic Gastritis`);
};
window.openConsultation = () => {
document.getElementById("rxDiagnosis").value = document.querySelector(".patient-meta").innerText.split(' • ')[1] || "";
modal.style.display = "block";
};
window.shareSummary = () => alert("📤 Summary sent to Patient's WhatsApp.");
window.printSummary = () => alert("🖨️ Printing Handover Note...");
window.toggleSidebar = () => {
const sb = document.getElementById('sidebar');
sb.style.display = (sb.style.display === 'flex') ? 'none' : 'flex';
};
// Global Listeners
if (closeModal) closeModal.onclick = () => modal.style.display = "none";
window.onclick = (e) => { if (e.target == modal) modal.style.display = "none"; };