thors1's picture
Initial DeepSite commit
76df546 verified
// Global State
let currentDate = new Date();
let currentFilter = 'all';
let isSidebarCollapsed = false;
// Sample Appointment Data
const appointments = [
{ id: 1, patient: "John Smith", time: "09:00 AM", type: "general", color: "bg-blue-500", date: 15 },
{ id: 2, patient: "Emma Wilson", time: "10:30 AM", type: "emergency", color: "bg-red-500", date: 15 },
{ id: 3, patient: "Michael Brown", time: "02:00 PM", type: "followup", color: "bg-green-500", date: 15 },
{ id: 4, patient: "Sarah Davis", time: "11:00 AM", type: "consultation", color: "bg-yellow-500", date: 16 },
{ id: 5, patient: "James Miller", time: "03:30 PM", type: "general", color: "bg-blue-500", date: 16 },
{ id: 6, patient: "Linda Garcia", time: "09:30 AM", type: "emergency", color: "bg-red-500", date: 17 },
{ id: 7, patient: "Robert Taylor", time: "01:00 PM", type: "followup", color: "bg-green-500", date: 18 },
{ id: 8, patient: "Patricia Martinez", time: "10:00 AM", type: "general", color: "bg-blue-500", date: 19 },
{ id: 9, patient: "William Anderson", time: "04:00 PM", type: "consultation", color: "bg-yellow-500", date: 20 },
{ id: 10, patient: "Elizabeth Thomas", time: "11:30 AM", type: "followup", color: "bg-green-500", date: 21 },
{ id: 11, patient: "David Jackson", time: "02:30 PM", type: "general", color: "bg-blue-500", date: 22 },
{ id: 12, patient: "Jennifer White", time: "09:00 AM", type: "emergency", color: "bg-red-500", date: 23 }
];
// Initialize
document.addEventListener('DOMContentLoaded', () => {
renderCalendar();
updateCurrentDate();
// Check window size for responsive sidebar
window.addEventListener('resize', handleResize);
handleResize();
});
// Sidebar Toggle
function toggleSidebar() {
const sidebar = document.getElementById('sidebar');
const mobileOverlay = document.getElementById('mobileOverlay');
const sidebarTexts = document.querySelectorAll('.sidebar-text');
if (window.innerWidth >= 1024) {
// Desktop behavior
isSidebarCollapsed = !isSidebarCollapsed;
if (isSidebarCollapsed) {
sidebar.classList.remove('w-64');
sidebar.classList.add('w-20');
sidebarTexts.forEach(text => {
text.style.opacity = '0';
text.style.width = '0';
text.style.overflow = 'hidden';
});
} else {
sidebar.classList.remove('w-20');
sidebar.classList.add('w-64');
sidebarTexts.forEach(text => {
text.style.opacity = '1';
text.style.width = 'auto';
text.style.overflow = 'visible';
});
}
} else {
// Mobile behavior
if (sidebar.classList.contains('-translate-x-full')) {
sidebar.classList.remove('-translate-x-full');
mobileOverlay.classList.remove('hidden');
} else {
sidebar.classList.add('-translate-x-full');
mobileOverlay.classList.add('hidden');
}
}
}
function handleResize() {
const sidebar = document.getElementById('sidebar');
const mobileOverlay = document.getElementById('mobileOverlay');
if (window.innerWidth >= 1024) {
mobileOverlay.classList.add('hidden');
if (!isSidebarCollapsed) {
sidebar.classList.remove('-translate-x-full');
sidebar.classList.add('w-64');
sidebar.classList.remove('w-20');
}
} else {
sidebar.classList.add('-translate-x-full');
sidebar.classList.remove('w-20');
sidebar.classList.add('w-64');
}
}
// Calendar Functions
function renderCalendar() {
const year = currentDate.getFullYear();
const month = currentDate.getMonth();
// Update header
const monthNames = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];
document.getElementById('calendarMonth').textContent = `${monthNames[month]} ${year}`;
const firstDay = new Date(year, month, 1).getDay();
const daysInMonth = new Date(year, month + 1, 0).getDate();
const daysInPrevMonth = new Date(year, month, 0).getDate();
const grid = document.getElementById('calendarGrid');
grid.innerHTML = '';
// Previous month days
for (let i = firstDay - 1; i >= 0; i--) {
const dayDiv = document.createElement('div');
dayDiv.className = 'calendar-day bg-gray-50 p-2 border-b border-r border-gray-200 min-h-[120px] text-gray-400';
dayDiv.innerHTML = `<span class="text-sm font-medium">${daysInPrevMonth - i}</span>`;
grid.appendChild(dayDiv);
}
// Current month days
const today = new Date();
for (let day = 1; day <= daysInMonth; day++) {
const dayDiv = document.createElement('div');
const isToday = today.getDate() === day && today.getMonth() === month && today.getFullYear() === year;
dayDiv.className = `calendar-day bg-white p-2 border-b border-r border-gray-200 min-h-[120px] hover:bg-gray-50 transition-colors cursor-pointer ${isToday ? 'bg-blue-50/30' : ''}`;
let dayContent = `<div class="flex justify-between items-start mb-1">
<span class="text-sm font-semibold ${isToday ? 'bg-blue-600 text-white w-7 h-7 flex items-center justify-center rounded-full' : 'text-gray-700'}">${day}</span>
</div>`;
// Add appointments for this day
const dayAppointments = appointments.filter(apt => apt.date === day);
if (currentFilter !== 'all') {
const filteredApts = dayAppointments.filter(apt => apt.type === currentFilter);
dayContent += generateAppointmentHTML(filteredApts);
} else {
dayContent += generateAppointmentHTML(dayAppointments);
}
dayDiv.innerHTML = dayContent;
dayDiv.onclick = () => openAddAppointment(day);
grid.appendChild(dayDiv);
}
// Next month days to fill grid
const remainingCells = 42 - (firstDay + daysInMonth);
for (let i = 1; i <= remainingCells; i++) {
const dayDiv = document.createElement('div');
dayDiv.className = 'calendar-day bg-gray-50 p-2 border-b border-r border-gray-200 min-h-[120px] text-gray-400';
dayDiv.innerHTML = `<span class="text-sm font-medium">${i}</span>`;
grid.appendChild(dayDiv);
}
}
function generateAppointmentHTML(appointments) {
if (appointments.length === 0) return '';
let html = '<div class="space-y-1 mt-1">';
appointments.slice(0, 3).forEach(apt => {
html += `
<div class="${apt.color} bg-opacity-10 border-l-2 ${apt.color.replace('bg-', 'border-')} px-2 py-1 rounded text-xs cursor-pointer hover:opacity-80 transition-opacity">
<p class="font-semibold text-gray-900 truncate">${apt.time}</p>
<p class="text-gray-600 truncate">${apt.patient}</p>
</div>
`;
});
if (appointments.length > 3) {
html += `<div class="text-xs text-gray-500 text-center mt-1">+${appointments.length - 3} more</div>`;
}
html += '</div>';
return html;
}
function changeMonth(direction) {
currentDate.setMonth(currentDate.getMonth() + direction);
renderCalendar();
}
function goToToday() {
currentDate = new Date();
renderCalendar();
}
function changeDateRange(value) {
if (value === 'today') {
// Filter to show only today's appointments in a list view (simplified for demo)
alert('Switched to Today view - showing today\'s schedule');
} else if (value === 'week') {
alert('Switched to Week view - showing weekly schedule');
}
// Month view is default
}
// Category Filter
function filterCategory(category) {
currentFilter = category;
// Update UI
document.querySelectorAll('.category-btn').forEach(btn => {
if (btn.dataset.category === category) {
btn.classList.remove('bg-white', 'text-gray-700', 'border', 'border-gray-200');
btn.classList.add('bg-gray-900', 'text-white');
btn.querySelector('span').classList.remove('category-dot');
if (category !== 'all') {
btn.querySelector('span').className = 'w-2 h-2 rounded-full bg-white';
}
} else {
btn.classList.add('bg-white', 'text-gray-700', 'border', 'border-gray-200');
btn.classList.remove('bg-gray-900', 'text-white');
const colors = {
'general': 'bg-blue-500 text-blue-500',
'emergency': 'bg-red-500 text-red-500',
'followup': 'bg-green-500 text-green-500',
'consultation': 'bg-yellow-500 text-yellow-500'
};
if (btn.dataset.category !== 'all') {
btn.querySelector('span').className = `w-2 h-2 rounded-full ${colors[btn.dataset.category]} category-dot`;
} else {
btn.querySelector('span').className = 'w-2 h-2 rounded-full bg-gray-900';
}
}
});
renderCalendar();
}
// Modal Functions
function openAddAppointment(day = null) {
const modal = document.getElementById('addModal');
modal.classList.remove('hidden');
lucide.createIcons();
}
function closeAddAppointment() {
document.getElementById('addModal').classList.add('hidden');
}
function saveAppointment() {
closeAddAppointment();
// Show success notification (simplified)
const notification = document.createElement('div');
notification.className = 'fixed bottom-4 right-4 bg-green-600 text-white px-6 py-3 rounded-lg shadow-lg z-50 fade-in flex items-center gap-2';
notification.innerHTML = '<i data-lucide="check-circle" class="w-5 h-5"></i> Appointment saved successfully!';
document.body.appendChild(notification);
lucide.createIcons();
setTimeout(() => {
notification.remove();
}, 3000);
}
// Export and Reports
function exportData() {
const notification = document.createElement('div');
notification.className = 'fixed bottom-4 right-4 bg-blue-600 text-white px-6 py-3 rounded-lg shadow-lg z-50 fade-in flex items-center gap-2';
notification.innerHTML = '<i data-lucide="download" class="w-5 h-5"></i> Exporting calendar data...';
document.body.appendChild(notification);
lucide.createIcons();
setTimeout(() => {
notification.innerHTML = '<i data-lucide="check-circle" class="w-5 h-5"></i> Export complete!';
setTimeout(() => notification.remove(), 2000);
}, 1500);
}
function generateReports() {
const notification = document.createElement('div');
notification.className = 'fixed bottom-4 right-4 bg-purple-600 text-white px-6 py-3 rounded-lg shadow-lg z-50 fade-in flex items-center gap-2';
notification.innerHTML = '<i data-lucide="file-text" class="w-5 h-5"></i> Generating report...';
document.body.appendChild(notification);
lucide.createIcons();
setTimeout(() => {
notification.innerHTML = '<i data-lucide="check-circle" class="w-5 h-5"></i> Report generated!';
setTimeout(() => notification.remove(), 2000);
}, 1500);
}
// Utility
function updateCurrentDate() {
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' };
document.getElementById('currentDateDisplay').textContent = new Date().toLocaleDateString('en-US', options);
}
// Close modal on outside click
document.getElementById('addModal').addEventListener('click', (e) => {
if (e.target === document.getElementById('addModal')) {
closeAddAppointment();
}
});