diff --git a/.Net Capstone Project/Dashboard27.js b/.Net Capstone Project/Dashboard27.js
new file mode 100644
index 0000000..9e56a5f
--- /dev/null
+++ b/.Net Capstone Project/Dashboard27.js
@@ -0,0 +1,832 @@
+let currentPatientId = null;
+let patientsCache = [];
+let patientSearchTerm = '';
+
+function showSpinner(show) {
+ document.getElementById('spinnerOverlay').style.display = show ? 'flex' : 'none';
+}
+
+function showToast(message, variant = 'success') {
+ const container = document.getElementById('toastContainer');
+ const el = document.createElement('div');
+ el.className = `toast align-items-center text-bg-${variant} border-0 show mb-2`;
+ el.innerHTML = `
+
+
${escapeHtml(p.fullName)}
+
${p.age} yrs · ${escapeHtml(p.gender)} · ${escapeHtml(p.medicalRecordNumber)}
+
ID: ${escapeHtml(p.id)}
+
+
+
+ `).join('');
+
+ container.querySelectorAll('.patient-tile').forEach(tile => {
+ tile.addEventListener('click', (e) => {
+ if (e.target.closest('[data-delete-patient]')) return;
+ selectPatient(tile.dataset.id);
+ });
+ });
+
+ container.querySelectorAll('[data-delete-patient]').forEach(btn => {
+ btn.addEventListener('click', async (e) => {
+ e.stopPropagation();
+ const id = btn.dataset.deletePatient;
+ if (!confirm('Delete this patient and all their chart data?')) return;
+ try {
+ showSpinner(true);
+ await Api.deletePatient(id);
+ showToast('Patient deleted.');
+ if (currentPatientId === id) {
+ currentPatientId = null;
+ sessionStorage.removeItem('cip_patientId');
+ document.getElementById('patientContent').classList.add('d-none');
+ document.getElementById('noPatientState').classList.remove('d-none');
+ }
+ await loadPatientList();
+ loadDashboardStats();
+ } catch (err) {
+ showToast(err.message, 'danger');
+ } finally {
+ showSpinner(false);
+ }
+ });
+ });
+}
+
+async function selectPatient(id) {
+ currentPatientId = id;
+ sessionStorage.setItem('cip_patientId', id);
+ renderPatientList();
+ updateStatCardsForContext();
+
+ document.getElementById('noPatientState').classList.add('d-none');
+ document.getElementById('patientContent').classList.remove('d-none');
+
+ resetRiskTab();
+ resetCdsTab();
+
+ await loadChart(id);
+ await loadCarePlans(id);
+}
+
+// ---------- Chart ----------
+async function loadChart(id) {
+ try {
+ showSpinner(true);
+ const chart = await Api.getChart(id);
+
+ document.getElementById('patientName').textContent = chart.fullName;
+ document.getElementById('patientMeta').textContent =
+ `${chart.age} yrs · ${chart.gender} · ${chart.medicalRecordNumber} · Patient ID: ${chart.patientId}`;
+
+ document.getElementById('conditionsList').innerHTML = chart.conditions.length
+ ? chart.conditions.map(c => `
+
+
+
${escapeHtml(c.display)}
+
${escapeHtml(c.code)} · ${escapeHtml(c.clinicalStatus)} · onset ${fmtDate(c.onsetDate)}
+
+
+
`).join('')
+ : 'No active conditions on file.
';
+
+ document.getElementById('allergiesList').innerHTML = chart.allergies.length
+ ? chart.allergies.map(a => `
+
+
+
${escapeHtml(a.substance)}
+
Reaction: ${escapeHtml(a.reaction)} · Criticality: ${escapeHtml(a.criticality)}
+
+
+
`).join('')
+ : 'No known allergies (NKA).
';
+
+ document.getElementById('medicationsList').innerHTML = chart.medications.length
+ ? chart.medications.map(m => `
+
+
+
${escapeHtml(m.medicationName)}
+
${escapeHtml(m.dosage)} · ${escapeHtml(m.status)} · authored ${fmtDate(m.authoredOn)}
+
+
+
`).join('')
+ : 'No active medications.
';
+
+ document.getElementById('observationsList').innerHTML = chart.observations.length
+ ? chart.observations.map(o => `
+
+
+
${escapeHtml(o.display)}: ${o.value} ${escapeHtml(o.unit)}
+
${fmtDate(o.effectiveDate)}
+
+
+
`).join('')
+ : 'No recent observations.
';
+
+ document.getElementById('encountersList').innerHTML = chart.encounters.length
+ ? chart.encounters.map(e => `
+
+
+
${escapeHtml(e.encounterType)} — ${escapeHtml(e.reason)}
+
${fmtDate(e.encounterDate)} · ${escapeHtml(e.status)}
+
+
+
`).join('')
+ : 'No encounters on file.
';
+
+ } catch (err) {
+ showToast(err.message, 'danger');
+ } finally {
+ showSpinner(false);
+ }
+}
+
+// ---------- Risk ----------
+function resetRiskTab() {
+ document.getElementById('riskForm').reset();
+ document.getElementById('q_pain_val').textContent = '0';
+ document.getElementById('riskResultEmpty').classList.remove('d-none');
+ document.getElementById('riskResultBody').classList.add('d-none');
+}
+
+function setupRiskForm() {
+ const painInput = document.getElementById('q_pain');
+ painInput.addEventListener('input', () => {
+ document.getElementById('q_pain_val').textContent = painInput.value;
+ });
+
+ document.getElementById('riskForm').addEventListener('submit', async (e) => {
+ e.preventDefault();
+ if (!currentPatientId) return;
+
+ const questionnaire = {
+ smoker: document.getElementById('q_smoker').checked,
+ familyHistoryHeartDisease: document.getElementById('q_family').checked,
+ priorHospitalization: document.getElementById('q_hosp').checked,
+ bmi: document.getElementById('q_bmi').value ? parseFloat(document.getElementById('q_bmi').value) : null,
+ painScore: parseInt(document.getElementById('q_pain').value || '0', 10)
+ };
+
+ try {
+ showSpinner(true);
+ const result = await Api.assessRisk(currentPatientId, questionnaire);
+ renderRiskResult(result);
+ showToast('Risk assessment complete.');
+ } catch (err) {
+ showToast(err.message, 'danger');
+ } finally {
+ showSpinner(false);
+ }
+ });
+}
+
+function renderRiskResult(result) {
+ document.getElementById('riskResultEmpty').classList.add('d-none');
+ document.getElementById('riskResultBody').classList.remove('d-none');
+
+ const gauge = document.getElementById('scoreGauge');
+ gauge.textContent = result.score;
+ gauge.style.background = result.riskLevel === 'High'
+ ? 'radial-gradient(circle, #e74c3c, #c0392b)'
+ : 'radial-gradient(circle, #27ae60, #1e8449)';
+
+ const badge = document.getElementById('riskLevelBadge');
+ badge.textContent = `${result.riskLevel} Risk`;
+ badge.className = `risk-badge ${result.riskLevel}`;
+
+ document.getElementById('riskFactorsList').innerHTML = result.contributingFactors
+ .map(f => `Click "Evaluate Encounter" to screen for drug-allergy conflicts and guideline gaps.
';
+ document.getElementById('alertCountBadge').classList.add('d-none');
+}
+
+async function evaluateCds() {
+ if (!currentPatientId) return;
+ try {
+ showSpinner(true);
+ const result = await Api.evaluateCds(currentPatientId);
+ renderCdsAlerts(result);
+ } catch (err) {
+ showToast(err.message, 'danger');
+ } finally {
+ showSpinner(false);
+ }
+}
+
+function renderCdsAlerts(result) {
+ const container = document.getElementById('cdsAlertsContainer');
+ const badge = document.getElementById('alertCountBadge');
+
+ if (!result.hasAlerts) {
+ container.innerHTML = '✅
Nothing triggered — no CDS alerts for this encounter.
';
+ badge.classList.add('d-none');
+ return;
+ }
+
+ badge.textContent = result.alerts.length;
+ badge.classList.remove('d-none');
+
+ container.innerHTML = result.alerts.map(a => `
+ ✅
All alerts for this encounter have been actioned.
';
+ } else {
+ badge.textContent = remaining;
+ }
+
+ await loadCarePlans(currentPatientId);
+ } catch (err) {
+ showToast(err.message, 'danger');
+ } finally {
+ showSpinner(false);
+ }
+}
+
+// ---------- Care Plans ----------
+async function loadCarePlans(patientId) {
+ if (!patientId) return;
+ try {
+ const carePlans = await Api.getCarePlans(patientId);
+ const tbody = document.getElementById('carePlansTableBody');
+
+ tbody.innerHTML = carePlans.length
+ ? carePlans.map(cp => `
+