// Initialize Lucide Icons lucide.createIcons(); // Page Management const pages = { 'dashboard': { title: 'Enterprise Dashboard', subtitle: 'Real-time analytics and reporting' }, 'revenue': { title: 'Revenue Analytics', subtitle: 'Detailed revenue breakdown and forecasting' }, 'patient-intelligence': { title: 'Patient Intelligence', subtitle: 'Demographics, conditions, and patient analytics' }, 'expiring-patients': { title: 'Expiring Patient Reports', subtitle: 'Monitor and manage patient expiration risk' }, 'renewal-reports': { title: 'Renewal & Approval Reports', subtitle: 'Track renewal rates and approval metrics' }, 'provider-performance': { title: 'Provider Performance', subtitle: 'Provider analytics and performance tracking' }, 'appointment-reports': { title: 'Appointment Reports', subtitle: 'Appointment analytics and scheduling insights' }, 'one-click-reports': { title: 'One-Click Reports', subtitle: 'Pre-built reports for instant insights' }, 'custom-reports': { title: 'Custom Reports Builder', subtitle: 'Build, save, and schedule custom reports' } }; // Chart instances storage const charts = {}; // Initialize the application document.addEventListener('DOMContentLoaded', function() { initializeCharts(); initializeEventListeners(); }); // Page Navigation function showPage(pageId) { // Hide all pages document.querySelectorAll('.page').forEach(page => { page.classList.remove('active'); }); // Show selected page const pageElement = document.getElementById(pageId); if (pageElement) { pageElement.classList.add('active'); // Update page title const pageInfo = pages[pageId]; if (pageInfo) { document.getElementById('page-title').textContent = pageInfo.title; document.getElementById('page-subtitle').textContent = pageInfo.subtitle; } // Update navigation active state document.querySelectorAll('.nav-item').forEach(item => { item.classList.remove('active', 'bg-primary-light', 'text-primary'); item.classList.add('text-gray-700', 'hover:bg-gray-100'); }); const activeNav = document.querySelector(`[onclick="showPage('${pageId}')"]`); if (activeNav) { activeNav.classList.add('active', 'bg-primary-light', 'text-primary'); activeNav.classList.remove('text-gray-700', 'hover:bg-gray-100'); } // Refresh charts for the new page setTimeout(() => { refreshPageCharts(pageId); }, 100); } } // Slide-out Panel Management function openSlideOut(panelId) { const panel = document.getElementById('slide-out-panel'); panel.classList.add('open'); // Load panel content based on panelId loadPanelContent(panelId); } function closeSlideOut() { const panel = document.getElementById('slide-out-panel'); panel.classList.remove('open'); } // Modal Management function openModal(modalId) { const modal = document.getElementById(modalId); if (modal) { modal.classList.remove('hidden'); modal.classList.add('flex'); } } function closeModal(modalId) { const modal = document.getElementById(modalId); if (modal) { modal.classList.add('hidden'); modal.classList.remove('flex'); } } // Initialize Charts function initializeCharts() { // Revenue Trend Chart const revenueCtx = document.getElementById('revenueTrendChart'); if (revenueCtx) { charts.revenueTrend = new Chart(revenueCtx, { type: 'line', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], datasets: [{ label: 'Revenue ($)', data: [320000, 350000, 380000, 420000, 450000, 480000, 510000, 540000, 580000, 620000, 650000, 690000], borderColor: '#0e9692', backgroundColor: 'rgba(14, 150, 146, 0.1)', borderWidth: 3, fill: true, tension: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { mode: 'index', intersect: false } }, scales: { y: { beginAtZero: false, grid: { display: true, color: 'rgba(0, 0, 0, 0.05)' }, ticks: { callback: function(value) { return '$' + (value / 1000).toFixed(0) + 'K'; } } }, x: { grid: { display: false } } } } }); } // Patient Distribution Chart const patientCtx = document.getElementById('patientDistributionChart'); if (patientCtx) { charts.patientDistribution = new Chart(patientCtx, { type: 'doughnut', data: { labels: ['Chronic Pain', 'Anxiety', 'Sleep Disorders', 'PTSD', 'Cancer', 'Other'], datasets: [{ data: [35, 25, 15, 12, 8, 5], backgroundColor: [ '#0e9692', '#10b981', '#3b82f6', '#8b5cf6', '#ec4899', '#6b7280' ], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom', labels: { padding: 20, usePointStyle: true } } } } }); } // Expiring Chart const expiringCtx = document.getElementById('expiringChart'); if (expiringCtx) { charts.expiring = new Chart(expiringCtx, { type: 'doughnut', data: { labels: ['Expiring', 'Active'], datasets: [{ data: [312, 8430], backgroundColor: ['#f59e0b', '#0e9692'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } } } }); } // Revenue by Category Chart const categoryCtx = document.getElementById('revenueByCategoryChart'); if (categoryCtx) { charts.revenueByCategory = new Chart(categoryCtx, { type: 'bar', data: { labels: ['Consultations', 'Products', 'Renewals', 'Follow-ups', 'Other'], datasets: [{ label: 'Revenue ($)', data: [185000, 245000, 98000, 65000, 42000], backgroundColor: '#0e9692', borderRadius: 6 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { display: true, color: 'rgba(0, 0, 0, 0.05)' }, ticks: { callback: function(value) { return '$' + (value / 1000).toFixed(0) + 'K'; } } }, x: { grid: { display: false } } } } }); } // Monthly Revenue Chart const monthlyCtx = document.getElementById('monthlyRevenueChart'); if (monthlyCtx) { charts.monthlyRevenue = new Chart(monthlyCtx, { type: 'line', data: { labels: ['Week 1', 'Week 2', 'Week 3', 'Week 4'], datasets: [{ label: 'Current Month', data: [85000, 92000, 98000, 105000], borderColor: '#0e9692', backgroundColor: 'rgba(14, 150, 146, 0.1)', borderWidth: 3, fill: true, tension: 0.4 }, { label: 'Previous Month', data: [82000, 88000, 91000, 95000], borderColor: '#9ca3af', backgroundColor: 'transparent', borderWidth: 2, borderDash: [5, 5], tension: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top', labels: { usePointStyle: true } } }, scales: { y: { beginAtZero: false, grid: { display: true, color: 'rgba(0, 0, 0, 0.05)' }, ticks: { callback: function(value) { return '$' + (value / 1000).toFixed(0) + 'K'; } } }, x: { grid: { display: false } } } } }); } // Age Distribution Chart const ageCtx = document.getElementById('ageDistributionChart'); if (ageCtx) { charts.ageDistribution = new Chart(ageCtx, { type: 'bar', data: { labels: ['18-25', '26-35', '36-45', '46-55', '56-65', '65+'], datasets: [{ label: 'Patients', data: [12, 28, 35, 25, 15, 5], backgroundColor: '#0e9692', borderRadius: 6 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: true, grid: { display: true, color: 'rgba(0, 0, 0, 0.05)' }, ticks: { callback: function(value) { return value + '%'; } } }, x: { grid: { display: false } } } } }); } // Conditions Chart const conditionsCtx = document.getElementById('conditionsChart'); if (conditionsCtx) { charts.conditions = new Chart(conditionsCtx, { type: 'polarArea', data: { labels: ['Chronic Pain', 'Anxiety', 'Insomnia', 'PTSD', 'Cancer', 'Migraine'], datasets: [{ data: [42, 28, 15, 8, 4, 3], backgroundColor: [ '#0e9692', '#10b981', '#3b82f6', '#8b5cf6', '#ec4899', '#f59e0b' ], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom', labels: { padding: 20, usePointStyle: true } } } } }); } // Growth Gauge Chart const growthCtx = document.getElementById('growthGauge'); if (growthCtx) { charts.growthGauge = new Chart(growthCtx, { type: 'doughnut', data: { labels: ['Growth', 'Remaining'], datasets: [{ data: [24.8, 75.2], backgroundColor: ['#0e9692', '#e5e7eb'], borderWidth: 0 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { callbacks: { label: function(context) { return context.label + ': ' + context.parsed + '%'; } } } }, cutout: '80%' } }); } // Provider Trend Chart for slide-out const providerTrendCtx = document.getElementById('providerTrendChart'); if (providerTrendCtx) { charts.providerTrend = new Chart(providerTrendCtx, { type: 'line', data: { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], datasets: [{ label: 'Satisfaction Score', data: [88, 90, 92, 91, 94, 95], borderColor: '#0e9692', backgroundColor: 'rgba(14, 150, 146, 0.1)', borderWidth: 3, fill: true, tension: 0.4 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { beginAtZero: false, min: 85, max: 100, grid: { display: true, color: 'rgba(0, 0, 0, 0.05)' }, ticks: { callback: function(value) { return value + '%'; } } }, x: { grid: { display: false } } } } }); } } // Initialize Event Listeners function initializeEventListeners() { // Close modals when clicking outside document.querySelectorAll('[id$="-modal"]').forEach(modal => { modal.addEventListener('click', function(e) { if (e.target === this) { closeModal(modal.id); } }); }); // Close slide-out when clicking outside const slideOut = document.getElementById('slide-out-panel'); if (slideOut) { slideOut.addEventListener('click', function(e) { if (e.target === this) { closeSlideOut(); } }); } // Close report detail panel when clicking outside const reportPanel = document.getElementById('report-detail-panel'); if (reportPanel) { reportPanel.addEventListener('click', function(e) { if (e.target === this) { closeSlideOut(); } }); } // Escape key to close modals document.addEventListener('keydown', function(e) { if (e.key === 'Escape') { closeSlideOut(); closeModal('report-detail-panel'); document.querySelectorAll('[id$="-modal"]').forEach(modal => { if (!modal.classList.contains('hidden')) { closeModal(modal.id); } }); } }); // Initialize drag and drop for custom reports initializeDragAndDrop(); } // Refresh charts for specific page function refreshPageCharts(pageId) { switch(pageId) { case 'dashboard': if (charts.revenueTrend) charts.revenueTrend.update(); if (charts.patientDistribution) charts.patientDistribution.update(); if (charts.expiring) charts.expiring.update(); break; case 'revenue': if (charts.revenueByCategory) charts.revenueByCategory.update(); if (charts.monthlyRevenue) charts.monthlyRevenue.update(); if (charts.growthGauge) charts.growthGauge.update(); break; case 'patient-intelligence': if (charts.ageDistribution) charts.ageDistribution.update(); if (charts.conditions) charts.conditions.update(); break; } } // Load panel content function loadPanelContent(panelId) { // In a real application, this would fetch content from a server // For demo, we'll just update some elements console.log('Loading panel content for:', panelId); } // Generate Report function generateReport(reportType) { const reports = { 'monthly-performance': { title: 'Monthly Performance Report', message: 'Generating comprehensive monthly performance report...' }, 'provider-metrics': { title: 'Provider Metrics Report', message: 'Creating detailed provider performance analysis...' }, 'expiration-risk': { title: 'Expiration Risk Report', message: 'Compiling expiration risk assessment...' }, 'ai-recommendations': { title: 'AI Recommendations Report', message: 'Generating personalized AI recommendations...' } }; const report = reports[reportType]; if (report) { // Show loading state const button = event.target.closest('button'); const originalText = button ? button.innerHTML : ''; if (button) { button.innerHTML = ' Generating...'; button.disabled = true; } // Simulate report generation setTimeout(() => { if (button) { button.innerHTML = originalText; button.disabled = false; } // Show success message alert(`✅ ${report.title} generated successfully!`); // In a real app, this would download the report console.log(`Generated report: ${reportType}`); }, 1500); } } // Export Report function exportReport() { // Show loading const button = event.target; const originalText = button.innerHTML; button.innerHTML = ' Exporting...'; button.disabled = true; // Simulate export process setTimeout(() => { button.innerHTML = originalText; button.disabled = false; closeModal('export-modal'); // Show success alert('✅ Report exported successfully! The download will begin shortly.'); }, 2000); } // Initialize tooltips function initializeTooltips() { // This would initialize tooltip library in a real app console.log('Tooltips initialized'); } // Custom Reports Functions function initializeDragAndDrop() { const draggableComponents = document.querySelectorAll('.draggable-component'); const reportCanvas = document.getElementById('report-canvas'); draggableComponents.forEach(component => { component.addEventListener('dragstart', function(e) { e.dataTransfer.setData('text/plain', this.dataset.component); this.classList.add('opacity-50'); }); component.addEventListener('dragend', function() { this.classList.remove('opacity-50'); }); }); if (reportCanvas) { reportCanvas.addEventListener('dragover', function(e) { e.preventDefault(); this.classList.add('border-primary', 'border-solid'); this.classList.remove('border-dashed', 'border-gray-300'); }); reportCanvas.addEventListener('dragleave', function() { this.classList.remove('border-primary', 'border-solid'); this.classList.add('border-dashed', 'border-gray-300'); }); reportCanvas.addEventListener('drop', function(e) { e.preventDefault(); this.classList.remove('border-primary', 'border-solid'); this.classList.add('border-dashed', 'border-gray-300'); const componentType = e.dataTransfer.getData('text/plain'); addComponentToCanvas(componentType); }); } } function addComponentToCanvas(type) { const canvas = document.getElementById('report-canvas'); // Remove placeholder if present const placeholder = canvas.querySelector('.text-center'); if (placeholder) { placeholder.remove(); } let componentHTML = ''; switch(type) { case 'kpi': componentHTML = `

KPI Component

Metric 1

$12,450

Metric 2

84.2%

`; break; case 'chart': componentHTML = `

Chart Component

Chart preview will appear here

`; break; case 'table': componentHTML = `

Table Component

Column 1 Column 2 Column 3
Data 1 Data 2 Data 3
Data 4 Data 5 Data 6
`; break; case 'filter': componentHTML = `

Filter Component

`; break; } canvas.insertAdjacentHTML('beforeend', componentHTML); lucide.createIcons(); } function removeComponent(button) { const component = button.closest('.bg-gray-50'); if (component) { component.remove(); // Show placeholder if canvas is empty const canvas = document.getElementById('report-canvas'); if (canvas.children.length === 0) { canvas.innerHTML = `

Drag and drop components here to build your report

Start by dragging components from the left panel

`; } } } function clearCanvas() { const canvas = document.getElementById('report-canvas'); if (canvas) { canvas.innerHTML = `

Drag and drop components here to build your report

Start by dragging components from the left panel

`; } } function saveCustomReport() { const button = event.target; const originalText = button.innerHTML; button.innerHTML = ' Saving...'; button.disabled = true; setTimeout(() => { button.innerHTML = originalText; button.disabled = false; alert('✅ Custom report saved successfully!'); }, 1500); } function generateCustomReport() { const button = event.target; const originalText = button.innerHTML; button.innerHTML = ' Generating...'; button.disabled = true; setTimeout(() => { button.innerHTML = originalText; button.disabled = false; alert('✅ Custom report generated successfully!\n\nThe report has been added to your saved reports and is ready for export.'); }, 2000); } function previewReport() { alert('🔍 Report Preview\n\nThis would open a preview of your custom report in a new window or modal.'); } function createNewReport() { const button = event.target; const originalText = button.innerHTML; button.innerHTML = ' Creating...'; button.disabled = true; setTimeout(() => { button.innerHTML = originalText; button.disabled = false; closeModal('new-report-modal'); alert('✅ New report template created!\n\nYou can now start building your custom report by dragging components to the canvas.'); }, 1500); } function runReport(reportId) { const button = event.target; const originalText = button.innerHTML; button.innerHTML = ' Running...'; button.disabled = true; setTimeout(() => { button.innerHTML = originalText; button.disabled = false; alert(`✅ Report "${reportId}" executed successfully!\n\nThe report has been generated and is ready for review.`); }, 2000); } function deleteReport(reportId) { if (confirm(`Are you sure you want to delete the "${reportId}" report? This action cannot be undone.`)) { const button = event.target; const row = button.closest('tr'); button.innerHTML = ''; button.disabled = true; setTimeout(() => { row.style.opacity = '0.5'; setTimeout(() => { row.remove(); alert(`✅ Report "${reportId}" has been deleted.`); }, 300); }, 1000); } } function saveReportConfig() { const button = event.target; const originalText = button.innerHTML; button.innerHTML = ' Saving...'; button.disabled = true; setTimeout(() => { button.innerHTML = originalText; button.disabled = false; closeSlideOut(); alert('✅ Report configuration saved successfully!'); }, 1500); } function testReport() { const button = event.target; const originalText = button.innerHTML; button.innerHTML = ' Testing...'; button.disabled = true; setTimeout(() => { button.innerHTML = originalText; button.disabled = false; alert('✅ Report test completed successfully!\n\nThe test report has been generated and sent to your email for review.'); }, 2000); } // Search functionality function initializeSearch() { const searchInput = document.querySelector('input[placeholder="Search reports..."]'); if (searchInput) { searchInput.addEventListener('keypress', function(e) { if (e.key === 'Enter') { const query = this.value.trim(); if (query) { performSearch(query); } } }); } } function performSearch(query) { console.log('Searching for:', query); // In a real app, this would make an API call alert(`Searching for: ${query}\n\nThis would show search results in a real application.`); } // Initialize search on load initializeSearch();