thors1's picture
🐳 11/04 - 19:43 - 🚨 SURGICAL ADD — TYPE OF VISIT (WALK IN / TELEHEALTH) VERIFY MC DESIGN SYSTEM LOCK — INCLUDE CURRENT SELECTION SYSTEM CRITICAL RULE: DO NOT change: * layout grid * card widths * sp
38892a6 verified
Raw
History Blame Contribute Delete
9.82 kB
// Sidebar Toggle Functionality
const sidebar = document.getElementById('sidebar');
const sidebarToggle = document.getElementById('sidebarToggle');
const mobileMenuBtn = document.getElementById('mobileMenuBtn');
let isSidebarCollapsed = false;
function toggleSidebar() {
isSidebarCollapsed = !isSidebarCollapsed;
if (window.innerWidth >= 1024) {
// Desktop behavior
if (isSidebarCollapsed) {
sidebar.classList.add('collapsed');
sidebar.style.width = '5rem';
} else {
sidebar.classList.remove('collapsed');
sidebar.style.width = '16rem';
}
} else {
// Mobile behavior - slide in/out
sidebar.classList.toggle('open');
// Create or toggle overlay
let overlay = document.querySelector('.sidebar-overlay');
if (!overlay) {
overlay = document.createElement('div');
overlay.className = 'sidebar-overlay';
document.body.appendChild(overlay);
overlay.addEventListener('click', toggleSidebar);
}
overlay.classList.toggle('open');
}
// Refresh Lucide icons after transition
setTimeout(() => {
lucide.createIcons();
}, 300);
}
sidebarToggle.addEventListener('click', toggleSidebar);
mobileMenuBtn.addEventListener('click', toggleSidebar);
// Patient Type Toggle
const existingPatientBtn = document.getElementById('existingPatientBtn');
const newPatientBtn = document.getElementById('newPatientBtn');
const existingPatientForm = document.getElementById('existingPatientForm');
const newPatientForm = document.getElementById('newPatientForm');
existingPatientBtn.addEventListener('click', () => {
existingPatientBtn.classList.add('bg-white', 'text-slate-800', 'shadow-sm');
existingPatientBtn.classList.remove('text-slate-600');
newPatientBtn.classList.remove('bg-white', 'text-slate-800', 'shadow-sm');
newPatientBtn.classList.add('text-slate-600');
existingPatientForm.classList.remove('hidden');
newPatientForm.classList.add('hidden');
});
newPatientBtn.addEventListener('click', () => {
newPatientBtn.classList.add('bg-white', 'text-slate-800', 'shadow-sm');
newPatientBtn.classList.remove('text-slate-600');
existingPatientBtn.classList.remove('bg-white', 'text-slate-800', 'shadow-sm');
existingPatientBtn.classList.add('text-slate-600');
newPatientForm.classList.remove('hidden');
existingPatientForm.classList.add('hidden');
});
// Time Slot Generation
const timeSlotsContainer = document.getElementById('timeSlotsContainer');
const appointmentDate = document.getElementById('appointmentDate');
const selectedDateDisplay = document.getElementById('selectedDateDisplay');
const confirmBtn = document.getElementById('confirmAppointmentBtn');
// Generate time slots (9 AM to 5 PM, 30 min intervals)
function generateTimeSlots() {
const slots = [];
const startHour = 9;
const endHour = 17;
for (let hour = startHour; hour < endHour; hour++) {
for (let min of [0, 30]) {
const time = `${hour.toString().padStart(2, '0')}:${min.toString().padStart(2, '0')}`;
// Randomly make some slots unavailable for realism
const isAvailable = Math.random() > 0.3;
slots.push({ time, isAvailable });
}
}
return slots;
}
function renderTimeSlots(date) {
if (!date) {
timeSlotsContainer.innerHTML = `
<div class="col-span-2 text-center py-8 text-slate-400">
<i data-lucide="calendar-days" class="w-12 h-12 mx-auto mb-3 opacity-50"></i>
<p class="text-sm">Please select a date to view available times</p>
</div>
`;
lucide.createIcons();
confirmBtn.disabled = true;
return;
}
// Show loading state briefly
timeSlotsContainer.innerHTML = '<div class="col-span-2 text-center py-4"><div class="loading-spinner w-6 h-6 border-2 border-teal-600 border-t-transparent rounded-full animate-spin mx-auto"></div></div>';
setTimeout(() => {
const slots = generateTimeSlots();
let html = '';
slots.forEach(slot => {
const statusClass = slot.isAvailable ? 'available bg-white border-slate-200 text-slate-700 hover:border-teal-400' : 'disabled';
const clickHandler = slot.isAvailable ? `onclick="selectTimeSlot(this, '${slot.time}')"` : '';
html += `
<button type="button" ${clickHandler}
class="time-slot ${statusClass} px-3 py-2 rounded-lg border text-sm font-medium transition-all"
${!slot.isAvailable ? 'disabled' : ''}>
${formatTime(slot.time)}
</button>
`;
});
timeSlotsContainer.innerHTML = html;
// Update date display
const dateObj = new Date(date);
selectedDateDisplay.textContent = dateObj.toLocaleDateString('en-US', {
weekday: 'short',
month: 'short',
day: 'numeric'
});
lucide.createIcons();
}, 300);
}
function formatTime(time) {
const [hours, minutes] = time.split(':');
const hour = parseInt(hours);
const ampm = hour >= 12 ? 'PM' : 'AM';
const displayHour = hour > 12 ? hour - 12 : (hour === 0 ? 12 : hour);
return `${displayHour}:${minutes} ${ampm}`;
}
let selectedTime = null;
function selectTimeSlot(element, time) {
// Remove selected class from all slots
document.querySelectorAll('.time-slot.available').forEach(slot => {
slot.classList.remove('selected');
});
// Add selected class to clicked slot
element.classList.add('selected');
selectedTime = time;
// Update time display in header
const timeDisplay = document.getElementById('selectedTimeDisplay');
if (timeDisplay) {
timeDisplay.textContent = formatTime(time);
timeDisplay.classList.remove('text-slate-400');
timeDisplay.classList.add('text-teal-600', 'font-medium');
}
// Enable confirm button
confirmBtn.disabled = false;
confirmBtn.textContent = `Confirm at ${formatTime(time)}`;
}
// Date change handler
appointmentDate.addEventListener('change', (e) => {
renderTimeSlots(e.target.value);
// Auto-scroll to right panel time slots on date selection
if (e.target.value && window.innerWidth >= 1280) {
const timePanel = document.querySelector('.xl\\:col-span-1');
if (timePanel) {
timePanel.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}
});
// Type of Visit Selection
const visitTypeButtons = document.querySelectorAll('.visit-type-btn');
let selectedVisitType = 'walk_in';
visitTypeButtons.forEach(button => {
button.addEventListener('click', () => {
// Remove selected state from all buttons
visitTypeButtons.forEach(btn => {
btn.setAttribute('data-selected', 'false');
});
// Add selected state to clicked button
button.setAttribute('data-selected', 'true');
selectedVisitType = button.getAttribute('data-value');
});
});
// Initialize with today's date
const today = new Date().toISOString().split('T')[0];
appointmentDate.value = today;
appointmentDate.min = today;
renderTimeSlots(today);
// Physician change simulation
const physicianSelect = document.getElementById('physicianSelect');
physicianSelect.addEventListener('change', () => {
if (appointmentDate.value) {
// Re-render slots with slight delay to simulate fetching new availability
renderTimeSlots(appointmentDate.value);
}
});
// Confirm button handler
confirmBtn.addEventListener('click', () => {
if (selectedTime && appointmentDate.value) {
// Show success animation
confirmBtn.innerHTML = '<i data-lucide="check" class="w-5 h-5 inline mr-2"></i> Appointment Saved!';
confirmBtn.classList.remove('bg-teal-600', 'hover:bg-teal-700');
confirmBtn.classList.add('bg-green-600', 'hover:bg-green-700');
lucide.createIcons();
// Reset after 2 seconds
setTimeout(() => {
confirmBtn.textContent = 'Confirm Appointment';
confirmBtn.classList.add('bg-teal-600', 'hover:bg-teal-700');
confirmBtn.classList.remove('bg-green-600', 'hover:bg-green-700');
confirmBtn.disabled = true;
// Clear selections
document.querySelectorAll('.time-slot.selected').forEach(slot => {
slot.classList.remove('selected');
});
selectedTime = null;
// Reset time display in header
const timeDisplay = document.getElementById('selectedTimeDisplay');
if (timeDisplay) {
timeDisplay.textContent = '--:--';
timeDisplay.classList.remove('text-teal-600', 'font-medium');
timeDisplay.classList.add('text-slate-400');
}
}, 2000);
}
});
// Responsive handling
window.addEventListener('resize', () => {
if (window.innerWidth >= 1024) {
// Reset to visible on desktop
sidebar.classList.remove('open');
const overlay = document.querySelector('.sidebar-overlay');
if (overlay) overlay.classList.remove('open');
} else {
// Reset collapsed state on mobile
if (isSidebarCollapsed) {
isSidebarCollapsed = false;
sidebar.classList.remove('collapsed');
sidebar.style.width = '16rem';
}
}
});
// Initialize Lucide icons on load
document.addEventListener('DOMContentLoaded', () => {
lucide.createIcons();
});