// Demo Patient Data const patients = [ { id: 1, firstName: "John", lastName: "Smith", mrn: "839214", status: "active", insurance: "BlueCross", insuranceProvider: "BlueCross", nextAppointment: "2026-04-02", expirationDate: "2026-05-12", clinic: "Los Angeles", lastVisit: "2026-03-01", phoneVerified: true, emailVerified: true, provider: "Dr. Smith", tags: ["new"] }, { id: 2, firstName: "Maria", lastName: "Gonzalez", mrn: "481992", status: "pending", insurance: "UnitedHealth", insuranceProvider: "UnitedHealth", nextAppointment: "2026-03-18", expirationDate: "2026-04-10", clinic: "San Diego", lastVisit: "2026-02-15", phoneVerified: true, emailVerified: false, provider: "Dr. Johnson", tags: ["followup"] }, { id: 3, firstName: "David", lastName: "Chen", mrn: "673204", status: "active", insurance: "Aetna", insuranceProvider: "Aetna", nextAppointment: "2026-04-06", expirationDate: "2026-06-02", clinic: "San Francisco", lastVisit: "2026-03-05", phoneVerified: true, emailVerified: true, provider: "Dr. Smith", tags: ["telehealth"] }, { id: 4, firstName: "Sarah", lastName: "Johnson", mrn: "904211", status: "approved", insurance: "Kaiser Permanente", insuranceProvider: "Kaiser", nextAppointment: "2026-04-01", expirationDate: "2026-05-20", clinic: "Los Angeles", lastVisit: "2026-03-10", phoneVerified: true, emailVerified: true, provider: "Dr. Williams", tags: [] }, { id: 5, firstName: "Michael", lastName: "Patel", mrn: "510992", status: "expired", insurance: "Medicare", insuranceProvider: "Medicare", nextAppointment: null, expirationDate: "2026-02-10", clinic: "San Jose", lastVisit: "2026-01-20", phoneVerified: false, emailVerified: true, provider: "Dr. Brown", tags: ["billing"] }, { id: 6, firstName: "Lisa", lastName: "Nguyen", mrn: "482311", status: "active", insurance: "BlueShield", insuranceProvider: "BlueShield", nextAppointment: "2026-03-29", expirationDate: "2026-07-08", clinic: "Sacramento", lastVisit: "2026-02-28", phoneVerified: true, emailVerified: true, provider: "Dr. Johnson", tags: [] }, { id: 7, firstName: "Robert", lastName: "Walker", mrn: "881420", status: "active", insurance: "UnitedHealth", insuranceProvider: "UnitedHealth", nextAppointment: "2026-04-05", expirationDate: "2026-06-14", clinic: "Los Angeles", lastVisit: "2026-03-08", phoneVerified: true, emailVerified: false, provider: "Dr. Smith", tags: ["allergy"] }, { id: 8, firstName: "Emily", lastName: "Carter", mrn: "640199", status: "pending", insurance: "Aetna", insuranceProvider: "Aetna", nextAppointment: "2026-03-20", expirationDate: "2026-04-22", clinic: "San Diego", lastVisit: "2026-02-25", phoneVerified: true, emailVerified: true, provider: "Dr. Williams", tags: ["new"] }, { id: 9, firstName: "Daniel", lastName: "Kim", mrn: "777200", status: "approved", insurance: "BlueCross", insuranceProvider: "BlueCross", nextAppointment: "2026-04-03", expirationDate: "2026-05-30", clinic: "San Francisco", lastVisit: "2026-03-12", phoneVerified: true, emailVerified: true, provider: "Dr. Brown", tags: ["telehealth"] }, { id: 10, firstName: "Jessica", lastName: "Brown", mrn: "223901", status: "archived", insurance: "Kaiser Permanente", insuranceProvider: "Kaiser", nextAppointment: null, expirationDate: null, clinic: "Fresno", lastVisit: "2025-12-15", phoneVerified: false, emailVerified: false, provider: "Dr. Johnson", tags: [] }, { id: 11, firstName: "Carlos", lastName: "Ramirez", mrn: "100239", status: "active", insurance: "Medicare", insuranceProvider: "Medicare", nextAppointment: "2026-03-25", expirationDate: "2026-05-05", clinic: "San Jose", lastVisit: "2026-02-20", phoneVerified: true, emailVerified: true, provider: "Dr. Smith", tags: [] }, { id: 12, firstName: "Olivia", lastName: "Taylor", mrn: "564009", status: "active", insurance: "BlueShield", insuranceProvider: "BlueShield", nextAppointment: "2026-04-04", expirationDate: "2026-06-18", clinic: "Los Angeles", lastVisit: "2026-03-15", phoneVerified: true, emailVerified: true, provider: "Dr. Williams", tags: ["new", "telehealth"] } ]; // State Management let currentPage = 1; let pageSize = 12; let selectedRows = new Set(); let filteredPatients = [...patients]; let currentFilters = { search: '', status: 'all', tag: 'all', insurance: 'all', provider: 'all', date: 'all' }; // Avatar Color Generator function getAvatarColor(id) { const colors = [ { bg: '#DBEAFE', text: '#1D4ED8' }, { bg: '#EDE9FE', text: '#6D28D9' }, { bg: '#FCE7F3', text: '#BE185D' }, { bg: '#D1FAE5', text: '#047857' }, { bg: '#FEF3C7', text: '#B45309' }, { bg: '#E0E7FF', text: '#4338CA' } ]; return colors[id % colors.length]; } // Date Formatting function formatDate(dateString) { if (!dateString) return '—'; const date = new Date(dateString); return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); } // Check if date is within 30 days or past due function getExpirationClass(dateString) { if (!dateString) return ''; const expDate = new Date(dateString); const today = new Date(); const diffTime = expDate - today; const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); if (diffDays < 0) return 'expiration-danger'; if (diffDays <= 30) return 'expiration-warning'; return ''; } function getExpirationText(dateString) { if (!dateString) return '—'; const expDate = new Date(dateString); const today = new Date(); const diffTime = expDate - today; const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); if (diffDays < 0) return 'Expired'; return formatDate(dateString); } // Render Patient Row function renderPatientRow(patient) { const avatarColors = getAvatarColor(patient.id); const initials = `${patient.firstName[0]}${patient.lastName[0]}`; const isSelected = selectedRows.has(patient.id); const expirationClass = getExpirationClass(patient.expirationDate); const expirationText = getExpirationText(patient.expirationDate); return `
${initials}
${patient.firstName} ${patient.lastName} ${patient.phoneVerified ? '' : ''} ${patient.emailVerified ? '' : ''}
MRN ${patient.mrn}
Last visit ${formatDate(patient.lastVisit)} • ${patient.clinic} Clinic
${patient.status.charAt(0).toUpperCase() + patient.status.slice(1)}
${patient.insurance}
${formatDate(patient.nextAppointment)}
${expirationText}
${patient.clinic}
`; } // Filter Logic function applyFilters() { filteredPatients = patients.filter(patient => { // Search filter if (currentFilters.search) { const searchLower = currentFilters.search.toLowerCase(); const fullName = `${patient.firstName} ${patient.lastName}`.toLowerCase(); const match = fullName.includes(searchLower) || patient.mrn.includes(searchLower) || patient.clinic.toLowerCase().includes(searchLower); if (!match) return false; } // Status filter if (currentFilters.status !== 'all' && patient.status !== currentFilters.status) { return false; } // Insurance filter if (currentFilters.insurance !== 'all' && patient.insuranceProvider !== currentFilters.insurance) { return false; } // Provider filter if (currentFilters.provider !== 'all' && patient.provider !== currentFilters.provider) { return false; } // Tag filter if (currentFilters.tag !== 'all' && !patient.tags.includes(currentFilters.tag)) { return false; } return true; }); currentPage = 1; render(); } // Render List function render() { const container = document.getElementById('patientList'); const start = (currentPage - 1) * pageSize; const end = start + pageSize; const pagePatients = filteredPatients.slice(start, end); if (pagePatients.length === 0) { container.innerHTML = ''; document.getElementById('emptyState').classList.remove('hidden'); } else { document.getElementById('emptyState').classList.add('hidden'); container.innerHTML = pagePatients.map(p => renderPatientRow(p)).join(''); lucide.createIcons(); } updatePagination(); updateBulkActions(); } // Pagination function updatePagination() { const total = filteredPatients.length; const start = (currentPage - 1) * pageSize + 1; const end = Math.min(currentPage * pageSize, total); document.getElementById('showingStart').textContent = total === 0 ? 0 : start; document.getElementById('showingEnd').textContent = end; document.getElementById('totalCount').textContent = total; document.getElementById('prevBtn').disabled = currentPage === 1; document.getElementById('nextBtn').disabled = end >= total; // Page numbers const totalPages = Math.ceil(total / pageSize); const pageContainer = document.getElementById('pageNumbers'); let html = ''; for (let i = 1; i <= totalPages; i++) { if (i === 1 || i === totalPages || (i >= currentPage - 1 && i <= currentPage + 1)) { html += ``; } else if (i === currentPage - 2 || i === currentPage + 2) { html += `...`; } } pageContainer.innerHTML = html; } function changePage(delta) { currentPage += delta; render(); window.scrollTo({ top: 0, behavior: 'smooth' }); } function goToPage(page) { currentPage = page; render(); window.scrollTo({ top: 0, behavior: 'smooth' }); } function changePageSize() { pageSize = parseInt(document.getElementById('pageSize').value); currentPage = 1; render(); } // Row Selection function toggleRowSelection(id) { if (selectedRows.has(id)) { selectedRows.delete(id); } else { selectedRows.add(id); } render(); } function handleRowClick(event, id) { // Navigate to patient details showToast(`Navigating to /patients/${id}`, 'info'); // Simulate navigation console.log(`Navigate to /patients/${id}`); } function toggleSelectAll() { const checkboxes = document.querySelectorAll('.row-checkbox'); const allSelected = selectedRows.size === filteredPatients.length; if (allSelected) { selectedRows.clear(); } else { filteredPatients.forEach(p => selectedRows.add(p.id)); } render(); } function clearSelection() { selectedRows.clear(); render(); } function updateBulkActions() { const bar = document.getElementById('bulkActionsBar'); const count = document.getElementById('selectedCount'); if (selectedRows.size > 0) { bar.classList.remove('hidden'); count.textContent = selectedRows.size; } else { bar.classList.add('hidden'); } // Update select all checkbox const selectAllCheckbox = document.getElementById('selectAll'); if (filteredPatients.length > 0 && selectedRows.size === filteredPatients.length) { selectAllCheckbox.checked = true; selectAllCheckbox.indeterminate = false; } else if (selectedRows.size > 0) { selectAllCheckbox.checked = false; selectAllCheckbox.indeterminate = true; } else { selectAllCheckbox.checked = false; selectAllCheckbox.indeterminate = false; } } function bulkAction(action) { showToast(`${action.charAt(0).toUpperCase() + action.slice(1)} ${selectedRows.size} patients (demo)`, 'success'); if (action === 'archive') { clearSelection(); } } // Dropdown Menu let activeDropdown = null; function toggleDropdown(event, patientId) { event.stopPropagation(); // Close existing if (activeDropdown) { activeDropdown.remove(); activeDropdown = null; return; } // Create new dropdown const template = document.getElementById('dropdownTemplate'); const dropdown = template.cloneNode(true); dropdown.id = 'activeDropdown'; dropdown.classList.remove('hidden'); // Position const button = event.currentTarget; const rect = button.getBoundingClientRect(); dropdown.style.position = 'fixed'; dropdown.style.top = `${rect.bottom + 4}px`; dropdown.style.right = `${window.innerWidth - rect.right}px`; dropdown.style.zIndex = '100'; document.body.appendChild(dropdown); activeDropdown = dropdown; lucide.createIcons(); // Close on outside click setTimeout(() => { document.addEventListener('click', closeDropdown, { once: true }); }, 0); } function closeDropdown() { if (activeDropdown) { activeDropdown.remove(); activeDropdown = null; } } function handleAction(action) { closeDropdown(); const messages = { view: 'Viewing patient details', edit: 'Opening patient editor', schedule: 'Opening scheduler', telehealth: 'Starting telehealth session', invoice: 'Invoice created (demo)', message: 'Message composer opened', upload: 'Document upload opened', archive: 'Patient archived (demo)' }; showToast(messages[action] || 'Action completed', action === 'archive' ? 'warning' : 'success'); } // More Filters Toggle function toggleMoreFilters() { const panel = document.getElementById('moreFilters'); panel.classList.toggle('hidden'); } // Toast Notifications function showToast(message, type = 'info') { const container = document.getElementById('toast-container'); const toast = document.createElement('div'); const colors = { success: 'bg-green-50 text-green-800 border-green-200', warning: 'bg-amber-50 text-amber-800 border-amber-200', error: 'bg-red-50 text-red-800 border-red-200', info: 'bg-blue-50 text-blue-800 border-blue-200' }; const icons = { success: 'check-circle', warning: 'alert-triangle', error: 'x-circle', info: 'info' }; toast.className = `${colors[type]} border rounded-lg px-4 py-3 shadow-lg flex items-center gap-3 min-w-[300px] animate-fade-up`; toast.innerHTML = ` ${message} `; container.appendChild(toast); lucide.createIcons(); setTimeout(() => { toast.style.opacity = '0'; toast.style.transform = 'translateX(100%)'; toast.style.transition = 'all 300ms ease'; setTimeout(() => toast.remove(), 300); }, 3000); } // Event Listeners document.getElementById('searchInput').addEventListener('input', (e) => { currentFilters.search = e.target.value; applyFilters(); }); document.getElementById('statusFilter').addEventListener('change', (e) => { currentFilters.status = e.target.value; applyFilters(); }); document.getElementById('insuranceFilter').addEventListener('change', (e) => { currentFilters.insurance = e.target.value; applyFilters(); }); document.getElementById('providerFilter').addEventListener('change', (e) => { currentFilters.provider = e.target.value; applyFilters(); }); document.getElementById('tagFilter').addEventListener('change', (e) => { currentFilters.tag = e.target.value; applyFilters(); }); document.getElementById('selectAll').addEventListener('change', toggleSelectAll); // Initialize document.addEventListener('DOMContentLoaded', () => { render(); lucide.createIcons(); });