// Sample data const appointments = [ { id: 'APT-2024-0092', date: '2024-01-15', time: '09:00 AM', duration: '30 min', provider: { name: 'Dr. Emily Chen', specialty: 'Internal Medicine', avatar: 'http://static.photos/people/320x240/2' }, category: 'Primary Care', type: 'In-person', location: 'Main Clinic, Room 304', status: 'Confirmed', notes: 2, reason: 'Annual physical examination', isUpcoming: true, history: [ { status: 'Created', time: 'Jan 8, 2024 2:30 PM', user: 'System' }, { status: 'Confirmed', time: 'Jan 8, 2024 2:35 PM', user: 'Dr. Chen' } ] }, { id: 'APT-2024-0095', date: '2024-01-18', time: '02:30 PM', duration: '45 min', provider: { name: 'Dr. James Wilson', specialty: 'Dermatology', avatar: 'http://static.photos/people/320x240/3' }, category: 'Dermatology', type: 'Telehealth', location: 'Video Consultation', status: 'Pending', notes: 0, reason: 'Rash follow-up consultation', isUpcoming: true, history: [ { status: 'Created', time: 'Jan 10, 2024 10:00 AM', user: 'Sarah Mitchell' } ] }, { id: 'APT-2024-0100', date: '2024-02-05', time: '11:00 AM', duration: '60 min', provider: { name: 'Dr. Sarah Park', specialty: 'Lab Services', avatar: 'http://static.photos/people/320x240/4' }, category: 'Lab', type: 'In-person', location: 'Lab Center, 2nd Floor', status: 'Confirmed', notes: 1, reason: 'Blood work and cholesterol panel', isUpcoming: true, history: [ { status: 'Created', time: 'Jan 20, 2024 9:00 AM', user: 'System' }, { status: 'Confirmed', time: 'Jan 20, 2024 9:15 AM', user: 'Staff' } ] }, { id: 'APT-2024-0085', date: '2023-12-15', time: '10:00 AM', duration: '30 min', provider: { name: 'Dr. Emily Chen', specialty: 'Internal Medicine', avatar: 'http://static.photos/people/320x240/2' }, category: 'Follow-up', type: 'In-person', location: 'Main Clinic, Room 304', status: 'Completed', notes: 3, reason: 'Medication review', isUpcoming: false, history: [ { status: 'Created', time: 'Dec 1, 2023 2:00 PM', user: 'System' }, { status: 'Confirmed', time: 'Dec 1, 2023 2:05 PM', user: 'Dr. Chen' }, { status: 'Checked-in', time: 'Dec 15, 2023 9:45 AM', user: 'Reception' }, { status: 'Completed', time: 'Dec 15, 2023 10:30 AM', user: 'Dr. Chen' } ] }, { id: 'APT-2024-0078', date: '2023-11-20', time: '03:00 PM', duration: '30 min', provider: { name: 'Dr. James Wilson', specialty: 'Dermatology', avatar: 'http://static.photos/people/320x240/3' }, category: 'Dermatology', type: 'In-person', location: 'Dermatology Suite, Room 105', status: 'Completed', notes: 2, reason: 'Skin examination', isUpcoming: false, history: [ { status: 'Created', time: 'Nov 10, 2023 11:00 AM', user: 'System' }, { status: 'Confirmed', time: 'Nov 10, 2023 11:05 AM', user: 'Auto-confirm' }, { status: 'Completed', time: 'Nov 20, 2023 3:30 PM', user: 'Dr. Wilson' } ] }, { id: 'APT-2024-0072', date: '2023-10-28', time: '09:30 AM', duration: '30 min', provider: { name: 'Dr. Emily Chen', specialty: 'Internal Medicine', avatar: 'http://static.photos/people/320x240/2' }, category: 'Primary Care', type: 'Telehealth', location: 'Phone Consultation', status: 'Canceled', notes: 0, reason: 'Prescription refill', isUpcoming: false, history: [ { status: 'Created', time: 'Oct 20, 2023 9:00 AM', user: 'Patient Portal' }, { status: 'Confirmed', time: 'Oct 20, 2023 9:05 AM', user: 'System' }, { status: 'Canceled', time: 'Oct 27, 2023 4:00 PM', user: 'Sarah Mitchell' } ] } ]; // State let currentView = 'list'; let currentCalendarView = 'month'; let selectedAppointment = null; // Initialize document.addEventListener('DOMContentLoaded', () => { renderListView(); renderCalendar(); renderUpcomingWeek(); // Re-initialize icons after all rendering is done if (typeof lucide !== 'undefined') { lucide.createIcons(); } }); // Sidebar Toggle function toggleSidebar() { const sidebar = document.getElementById('sidebar'); const overlay = document.getElementById('sidebarOverlay'); sidebar.classList.toggle('-translate-x-full'); overlay.classList.toggle('hidden'); } // Profile Dropdown function toggleProfileDropdown() { const dropdown = document.getElementById('profileDropdown'); dropdown.classList.toggle('hidden'); } // More Dropdown function toggleMoreDropdown() { const dropdown = document.getElementById('moreDropdown'); dropdown.classList.toggle('hidden'); } // Close dropdowns when clicking outside document.addEventListener('click', (e) => { if (!e.target.closest('.relative')) { const profileDropdown = document.getElementById('profileDropdown'); const moreDropdown = document.getElementById('moreDropdown'); if (profileDropdown) profileDropdown.classList.add('hidden'); if (moreDropdown) moreDropdown.classList.add('hidden'); } }); // View Switching function switchView(view) { currentView = view; const listView = document.getElementById('listView'); const calendarView = document.getElementById('calendarView'); const listBtn = document.getElementById('listViewBtn'); const calendarBtn = document.getElementById('calendarViewBtn'); const sortDropdown = document.getElementById('sortDropdown'); if (view === 'list') { listView.classList.remove('hidden'); calendarView.classList.add('hidden'); listBtn.classList.add('bg-teal-50', 'text-teal-700'); listBtn.classList.remove('text-gray-600', 'hover:text-gray-900'); calendarBtn.classList.remove('bg-teal-50', 'text-teal-700'); calendarBtn.classList.add('text-gray-600', 'hover:text-gray-900'); if (sortDropdown && sortDropdown.parentElement) { sortDropdown.parentElement.style.opacity = '1'; sortDropdown.parentElement.style.pointerEvents = 'auto'; } } else { listView.classList.add('hidden'); calendarView.classList.remove('hidden'); calendarBtn.classList.add('bg-teal-50', 'text-teal-700'); calendarBtn.classList.remove('text-gray-600', 'hover:text-gray-900'); listBtn.classList.remove('bg-teal-50', 'text-teal-700'); listBtn.classList.add('text-gray-600', 'hover:text-gray-900'); if (sortDropdown && sortDropdown.parentElement) { sortDropdown.parentElement.style.opacity = '0.5'; sortDropdown.parentElement.style.pointerEvents = 'none'; } } if (typeof lucide !== 'undefined') { lucide.createIcons(); } } // Render List View function renderListView() { const upcomingList = document.getElementById('upcomingList'); const historyList = document.getElementById('historyList'); const upcoming = appointments.filter(a => a.isUpcoming); const history = appointments.filter(a => !a.isUpcoming); if (upcomingList) { upcomingList.innerHTML = upcoming.map(appt => createAppointmentRow(appt)).join(''); } if (historyList) { historyList.innerHTML = history.map(appt => createAppointmentRow(appt)).join(''); } if (typeof lucide !== 'undefined') { lucide.createIcons(); } } function createAppointmentRow(appt) { if (!appt) return ''; const statusColors = { 'Confirmed': 'bg-green-100 text-green-700 border-green-200', 'Pending': 'bg-yellow-100 text-yellow-700 border-yellow-200', 'Completed': 'bg-gray-100 text-gray-700 border-gray-200', 'Canceled': 'bg-red-100 text-red-700 border-red-200', 'No-show': 'bg-orange-100 text-orange-700 border-orange-200' }; const categoryColors = { 'Primary Care': 'bg-blue-50 text-blue-700 border-blue-200', 'Dermatology': 'bg-purple-50 text-purple-700 border-purple-200', 'Lab': 'bg-pink-50 text-pink-700 border-pink-200', 'Follow-up': 'bg-indigo-50 text-indigo-700 border-indigo-200' }; const statusClass = statusColors[appt.status] || 'bg-gray-100 text-gray-700 border-gray-200'; const categoryClass = categoryColors[appt.category] || 'bg-gray-100 text-gray-700 border-gray-200'; return `
${formatDate(appt.date)}
${appt.time || ''} • ${appt.duration || ''}
${appt.provider?.name || ''}
${appt.provider?.specialty || ''}
${appt.category || ''}
${appt.type || ''}
${appt.location || ''} ${appt.status || ''} ${(appt.notes || 0) > 0 ? `
${appt.notes}
` : '-'}
`; } // Calendar Functions function setCalendarView(view) { currentCalendarView = view; document.getElementById('monthViewBtn').className = view === 'month' ? 'px-3 py-1.5 text-sm font-medium rounded-lg bg-teal-50 text-teal-700' : 'px-3 py-1.5 text-sm font-medium rounded-lg text-gray-600 hover:bg-gray-50'; document.getElementById('weekViewBtn').className = view === 'week' ? 'px-3 py-1.5 text-sm font-medium rounded-lg bg-teal-50 text-teal-700' : 'px-3 py-1.5 text-sm font-medium rounded-lg text-gray-600 hover:bg-gray-50'; document.getElementById('dayViewBtn').className = view === 'day' ? 'px-3 py-1.5 text-sm font-medium rounded-lg bg-teal-50 text-teal-700' : 'px-3 py-1.5 text-sm font-medium rounded-lg text-gray-600 hover:bg-gray-50'; } function renderCalendar() { const grid = document.getElementById('calendarGrid'); if (!grid) return; const daysInMonth = 31; // simplified const startDay = 1; // Monday let html = ''; // Empty cells for start of month for (let i = 0; i < startDay; i++) { html += `
`; } // Days for (let day = 1; day <= daysInMonth; day++) { const dayAppointments = appointments.filter(a => { if (!a || !a.date) return false; const apptDate = new Date(a.date); return apptDate && apptDate.getDate() === day; }); const isToday = day === 15; // Example html += `
${day} ${dayAppointments.length > 3 ? `+${dayAppointments.length - 2} more` : ''}
${dayAppointments.slice(0, 3).map(appt => { if (!appt || !appt.status) return ''; const statusColors = { 'Confirmed': 'border-l-teal-500', 'Pending': 'border-l-yellow-500', 'Completed': 'border-l-gray-400', 'Canceled': 'border-l-red-400' }; const lastName = appt.provider && appt.provider.name ? appt.provider.name.split(' ')[1] || '' : ''; return `
${appt.time || ''}
${lastName}
${appt.category || ''}
`; }).join('')}
`; } grid.innerHTML = html; } function renderUpcomingWeek() { const container = document.getElementById('upcomingWeekList'); if (!container) return; const upcoming = appointments.filter(a => a && a.isUpcoming).slice(0, 5); container.innerHTML = upcoming.map(appt => `
${formatDayOfWeek(appt.date)} ${appt.time || ''}
${appt.category || ''}
${appt.provider?.name || ''}
`).join(''); if (typeof lucide !== 'undefined') { lucide.createIcons(); } } // Drawer Functions function openDrawer(appointmentId) { const appt = appointments.find(a => a && a.id === appointmentId); if (!appt) return; selectedAppointment = appt; const overlay = document.getElementById('drawerOverlay'); const drawer = document.getElementById('appointmentDrawer'); const content = document.getElementById('drawerContent'); const apptIdEl = document.getElementById('drawerApptId'); if (!overlay || !drawer || !content || !apptIdEl) return; apptIdEl.textContent = appt.id; const statusColors = { 'Confirmed': 'text-green-700 bg-green-50 border-green-200', 'Pending': 'text-yellow-700 bg-yellow-50 border-yellow-200', 'Completed': 'text-gray-700 bg-gray-100 border-gray-200', 'Canceled': 'text-red-700 bg-red-50 border-red-200' }; const statusColors = { 'Confirmed': 'text-green-700 bg-green-50 border-green-200', 'Pending': 'text-yellow-700 bg-yellow-50 border-yellow-200', 'Completed': 'text-gray-700 bg-gray-100 border-gray-200', 'Canceled': 'text-red-700 bg-red-50 border-red-200' }; content.innerHTML = `
${formatDateFull(appt.date)}
${appt.time || ''} • ${appt.duration || ''}
${appt.status || ''}

Status Timeline

${(appt.history || []).map((h, i, arr) => `
${i < arr.length - 1 ? '
' : ''}
${h.status || ''}
${h.time || ''} • ${h.user || ''}
`).join('') || 'No history available'}
${appt.provider?.name || 'Unknown Provider'}
${appt.provider?.specialty || ''}
Category
${appt.category || ''}
Type
${appt.type || ''}
${appt.type === 'Telehealth' ? '' : ''}
Location
${appt.location || ''}
Reason for Visit

${appt.reason || ''}

Notes
${(appt.notes || 0) > 0 ? `
Jan 8, 2024 2:35 PM • Dr. Chen

Patient confirmed appointment via portal. No special requirements noted.

${appt.notes > 1 ? `
Jan 5, 2024 9:00 AM • Sarah M.

Requested morning slot due to work schedule.

` : ''}
` : '
No notes added yet
'}
`; overlay.classList.remove('hidden'); setTimeout(() => overlay.classList.remove('opacity-0'), 10); drawer.classList.remove('translate-x-full'); if (typeof lucide !== 'undefined') { lucide.createIcons(); } } function closeDrawer() { const overlay = document.getElementById('drawerOverlay'); const drawer = document.getElementById('appointmentDrawer'); overlay.classList.add('opacity-0'); drawer.classList.add('translate-x-full'); setTimeout(() => { overlay.classList.add('hidden'); }, 300); selectedAppointment = null; } // Modal Functions function openNewAppointmentModal() { const modal = document.getElementById('newAppointmentModal'); modal.classList.remove('hidden'); setTimeout(() => { modal.querySelector('div[class*="scale-100"]').classList.remove('scale-95', 'opacity-0'); }, 10); } function closeNewAppointmentModal() { const modal = document.getElementById('newAppointmentModal'); modal.classList.add('hidden'); } function saveAppointment() { // Simulate saving closeNewAppointmentModal(); // Show success notification (simplified) alert('Appointment scheduled successfully!'); } // New Note Modal Functions function openNewNoteModal() { const modal = document.getElementById('newNoteModal'); if (modal) { modal.classList.remove('hidden'); if (typeof lucide !== 'undefined') { lucide.createIcons(); } } } function closeNewNoteModal() { const modal = document.getElementById('newNoteModal'); modal.classList.add('hidden'); } function saveNote() { closeNewNoteModal(); alert('Note saved successfully!'); } // Notes view toggle (for tab switching - basic implementation) function showNotesView() { document.getElementById('listView').classList.add('hidden'); document.getElementById('calendarView').classList.add('hidden'); document.getElementById('notesSection').classList.remove('hidden'); } function hideNotesView() { document.getElementById('notesSection').classList.add('hidden'); } // Helper Functions function formatDate(dateStr) { if (!dateStr) return ''; const date = new Date(dateStr); if (isNaN(date.getTime())) return ''; return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); } function formatDateFull(dateStr) { if (!dateStr) return ''; const date = new Date(dateStr); if (isNaN(date.getTime())) return ''; return date.toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric' }); } function formatDayOfWeek(dateStr) { if (!dateStr) return ''; const date = new Date(dateStr); if (isNaN(date.getTime())) return ''; return date.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric' }); } function cancelAppointment(id) { if (confirm('Are you sure you want to cancel this appointment?')) { alert('Appointment canceled'); closeDrawer(); } } function sendReminder(id) { alert('Reminder sent to patient'); } // Keyboard shortcuts document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { closeDrawer(); closeNewAppointmentModal(); } });