Spaces:
Running
Running
| // State Management | |
| let currentPage = 'org-business'; | |
| let openMenus = ['org']; | |
| let commandHistory = []; | |
| // Menu Structure for Command Palette | |
| const commands = [ | |
| { id: 'org-business', label: 'Business Information', category: 'Organization', icon: 'building-2' }, | |
| { id: 'org-branding', label: 'Branding & Appearance', category: 'Organization', icon: 'palette' }, | |
| { id: 'org-locations', label: 'Location Management', category: 'Organization', icon: 'map-pin' }, | |
| { id: 'org-roles', label: 'Roles & Permissions', category: 'Organization', icon: 'shield' }, | |
| { id: 'org-audit', label: 'Audit Logs', category: 'Organization', icon: 'clipboard-list' }, | |
| { id: 'prov-directory', label: 'Provider Directory', category: 'Providers', icon: 'users' }, | |
| { id: 'prov-scheduling', label: 'Provider Scheduling', category: 'Providers', icon: 'calendar' }, | |
| { id: 'prov-compensation', label: 'Compensation Models', category: 'Providers', icon: 'dollar-sign' }, | |
| { id: 'prov-access', label: 'Access Control', category: 'Providers', icon: 'lock' }, | |
| { id: 'sched-types', label: 'Appointment Types', category: 'Scheduling', icon: 'calendar-clock' }, | |
| { id: 'sched-availability', label: 'Availability Rules', category: 'Scheduling', icon: 'clock' }, | |
| { id: 'sched-rules', label: 'Booking Rules', category: 'Scheduling', icon: 'rule' }, | |
| { id: 'sched-waitlist', label: 'Waitlist Settings', category: 'Scheduling', icon: 'list' }, | |
| { id: 'sched-noshow', label: 'No-Show Policy', category: 'Scheduling', icon: 'user-x' }, | |
| { id: 'bill-pricing', label: 'Service Pricing', category: 'Billing', icon: 'tag' }, | |
| { id: 'bill-subscriptions', label: 'Subscriptions', category: 'Billing', icon: 'repeat' }, | |
| { id: 'bill-invoices', label: 'Invoice Templates', category: 'Billing', icon: 'file-invoice' }, | |
| { id: 'bill-payouts', label: 'Payout Rules', category: 'Billing', icon: 'wallet' }, | |
| { id: 'comm-sms', label: 'SMS Configuration', category: 'Communications', icon: 'message-square' }, | |
| { id: 'comm-email', label: 'Email Templates', category: 'Communications', icon: 'mail' }, | |
| { id: 'comm-automation', label: 'Communication Automation', category: 'Communications', icon: 'zap' }, | |
| { id: 'forms-templates', label: 'Form Templates', category: 'Forms', icon: 'file-text' }, | |
| { id: 'forms-intake', label: 'Intake Forms', category: 'Forms', icon: 'clipboard' }, | |
| { id: 'forms-sign', label: 'eSignature Settings', category: 'Forms', icon: 'pen-tool' }, | |
| { id: 'comp-hipaa', label: 'HIPAA Controls', category: 'Compliance', icon: 'shield-check' }, | |
| { id: 'comp-consents', label: 'Consent Tracking', category: 'Compliance', icon: 'check-circle' }, | |
| { id: 'comp-security', label: 'Security Audit', category: 'Compliance', icon: 'search' }, | |
| { id: 'ai-automation', label: 'AI Workflows', category: 'AI & Automation', icon: 'sparkles' }, | |
| { id: 'ai-agents', label: 'AI Agents', category: 'AI & Automation', icon: 'bot' }, | |
| { id: 'ai-recommendations', label: 'AI Recommendations', category: 'AI & Automation', icon: 'lightbulb' }, | |
| { id: 'int-connected', label: 'Connected Apps', category: 'Integrations', icon: 'plug' }, | |
| { id: 'int-api', label: 'API Keys', category: 'Integrations', icon: 'key' }, | |
| { id: 'int-webhooks', label: 'Webhooks', category: 'Integrations', icon: 'webhook' }, | |
| { id: 'anl-kpis', label: 'KPI Configuration', category: 'Analytics', icon: 'bar-chart' }, | |
| { id: 'anl-forecasting', label: 'AI Forecasting', category: 'Analytics', icon: 'trending-up' }, | |
| { id: 'anl-exports', label: 'Data Exports', category: 'Analytics', icon: 'download' }, | |
| { id: 'pat-portal', label: 'Patient Portal', category: 'Patient Experience', icon: 'layout' }, | |
| { id: 'pat-booking', label: 'Booking Page', category: 'Patient Experience', icon: 'calendar-days' }, | |
| { id: 'pat-reviews', label: 'Review Management', category: 'Patient Experience', icon: 'star' }, | |
| { id: 'sec-mfa', label: 'Multi-Factor Auth', category: 'Security', icon: 'smartphone' }, | |
| { id: 'sec-access', label: 'Access Policies', category: 'Security', icon: 'lock' }, | |
| { id: 'sec-backup', label: 'Backup & Recovery', category: 'Security', icon: 'archive' }, | |
| { id: 'sys-performance', label: 'Performance', category: 'System', icon: 'gauge' }, | |
| { id: 'sys-logs', label: 'System Logs', category: 'System', icon: 'scroll-text' }, | |
| { id: 'sys-flags', label: 'Feature Flags', category: 'System', icon: 'toggle' }, | |
| { id: 'ent-locations', label: 'Enterprise Locations', category: 'Enterprise', icon: 'building' }, | |
| { id: 'ent-permissions', label: 'Enterprise Permissions', category: 'Enterprise', icon: 'users-2' }, | |
| { id: 'ent-sla', label: 'SLA Settings', category: 'Enterprise', icon: 'file-check' } | |
| ]; | |
| // Content Templates | |
| const pageContents = { | |
| 'org-business': { | |
| title: 'Business Information', | |
| badge: 'Core Settings', | |
| content: ` | |
| <div class="max-w-4xl fade-in space-y-6"> | |
| <div class="bg-white rounded-xl border border-gray-200 p-6 shadow-sm"> | |
| <h3 class="text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2"> | |
| <i data-lucide="building-2" class="w-5 h-5 text-primary"></i> | |
| Business Details | |
| </h3> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-gray-700">Organization Name</label> | |
| <input type="text" value="DeepSite Medical Center" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/20 focus:border-primary outline-none transition-all"> | |
| </div> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-gray-700">Legal Entity Name</label> | |
| <input type="text" value="DeepSite Healthcare LLC" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/20 focus:border-primary outline-none transition-all"> | |
| </div> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-gray-700">Tax ID / EIN</label> | |
| <input type="text" value="**-*******" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/20 focus:border-primary outline-none transition-all"> | |
| </div> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-gray-700">Phone Number</label> | |
| <input type="tel" value="+1 (555) 123-4567" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/20 focus:border-primary outline-none transition-all"> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl border border-gray-200 p-6 shadow-sm"> | |
| <h3 class="text-lg font-semibold text-gray-900 mb-4 flex items-center gap-2"> | |
| <i data-lucide="map-pin" class="w-5 h-5 text-primary"></i> | |
| Primary Address | |
| </h3> | |
| <div class="space-y-4"> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-gray-700">Street Address</label> | |
| <input type="text" value="123 Healthcare Avenue, Suite 100" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/20 focus:border-primary outline-none transition-all"> | |
| </div> | |
| <div class="grid grid-cols-3 gap-4"> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-gray-700">City</label> | |
| <input type="text" value="San Francisco" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/20 focus:border-primary outline-none transition-all"> | |
| </div> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-gray-700">State</label> | |
| <select class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/20 focus:border-primary outline-none transition-all bg-white"> | |
| <option>California</option> | |
| </select> | |
| </div> | |
| <div class="space-y-2"> | |
| <label class="text-sm font-medium text-gray-700">ZIP</label> | |
| <input type="text" value="94102" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/20 focus:border-primary outline-none transition-all"> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-gradient-to-r from-primary/5 to-primary-light/5 rounded-xl border border-primary/20 p-6"> | |
| <div class="flex items-start gap-4"> | |
| <div class="p-3 bg-white rounded-lg shadow-sm"> | |
| <i data-lucide="info" class="w-5 h-5 text-primary"></i> | |
| </div> | |
| <div> | |
| <h4 class="font-semibold text-gray-900 mb-1">Multi-Location Enabled</h4> | |
| <p class="text-sm text-gray-600 mb-3">You currently have 3 active locations. Manage location-specific settings in the Locations tab.</p> | |
| <button onclick="loadPage('org-locations')" class="text-sm font-medium text-primary hover:text-primary-dark flex items-center gap-1"> | |
| Manage Locations <i data-lucide="arrow-right" class="w-4 h-4"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ` | |
| }, | |
| 'org-branding': { | |
| title: 'Branding & Appearance', | |
| badge: 'Customization', | |
| content: ` | |
| <div class="max-w-4xl fade-in space-y-6"> | |
| <div class="bg-white rounded-xl border border-gray-200 p-6 shadow-sm"> | |
| <h3 class="text-lg font-semibold text-gray-900 mb-4">Brand Assets</h3> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div class="border-2 border-dashed border-gray-300 rounded-xl p-8 text-center hover:border-primary hover:bg-primary/5 transition-all cursor-pointer group"> | |
| <div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-3 group-hover:bg-white transition-colors"> | |
| <i data-lucide="upload" class="w-6 h-6 text-gray-400 group-hover:text-primary"></i> | |
| </div> | |
| <p class="text-sm font-medium text-gray-900 mb-1">Upload Logo</p> | |
| <p class="text-xs text-gray-500">SVG, PNG, JPG (max 2MB)</p> | |
| </div> | |
| <div class="border-2 border-dashed border-gray-300 rounded-xl p-8 text-center hover:border-primary hover:bg-primary/5 transition-all cursor-pointer group"> | |
| <div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-3 group-hover:bg-white transition-colors"> | |
| <i data-lucide="image" class="w-6 h-6 text-gray-400 group-hover:text-primary"></i> | |
| </div> | |
| <p class="text-sm font-medium text-gray-900 mb-1">Favicon</p> | |
| <p class="text-xs text-gray-500">ICO, PNG (32x32px)</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-white rounded-xl border border-gray-200 p-6 shadow-sm"> | |
| <h3 class="text-lg font-semibold text-gray-900 mb-4">Color Scheme</h3> | |
| <div class="space-y-4"> | |
| <div class="flex items-center justify-between p-4 bg-gray-50 rounded-lg"> | |
| <div class="flex items-center gap-3"> | |
| <div class="w-10 h-10 rounded-lg bg-[#0e9692] shadow-sm"></div> | |
| <div> | |
| <p class="text-sm font-medium text-gray-900">Primary Color</p> | |
| <p class="text-xs text-gray-500">#0e9692</p> | |
| </div> | |
| </div> | |
| <button class="text-sm text-primary font-medium hover:underline">Change</button> | |
| </div> | |
| <div class="flex items-center justify-between p-4 bg-gray-50 rounded-lg"> | |
| <div class="flex items-center gap-3"> | |
| <div class="w-10 h-10 rounded-lg bg-gray-900 shadow-sm"></div> | |
| <div> | |
| <p class="text-sm font-medium text-gray-900">Secondary Color</p> | |
| <p class="text-xs text-gray-500">#111827</p> | |
| </div> | |
| </div> | |
| <button class="text-sm text-primary font-medium hover:underline">Change</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| ` | |
| }, | |
| 'default': { | |
| title: 'Settings Page', | |
| badge: 'Configuration', | |
| content: ` | |
| <div class="max-w-4xl fade-in space-y-6"> | |
| <div class="bg-white rounded-xl border border-gray-200 p-12 shadow-sm text-center"> | |
| <div class="w-20 h-20 bg-primary/10 rounded-full flex items-center justify-center mx-auto mb-4"> | |
| <i data-lucide="settings" class="w-10 h-10 text-primary"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold text-gray-900 mb-2">Configuration Panel</h3> | |
| <p class="text-gray-500 max-w-md mx-auto mb-6">This settings module is currently under development. Check back soon for advanced configuration options.</p> | |
| <div class="flex items-center justify-center gap-3"> | |
| <button class="px-4 py-2 bg-primary text-white rounded-lg text-sm font-medium hover:bg-primary-dark transition-colors">Request Access</button> | |
| <button class="px-4 py-2 border border-gray-300 text-gray-700 rounded-lg text-sm font-medium hover:bg-gray-50 transition-colors">Documentation</button> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-4"> | |
| <div class="bg-white rounded-xl border border-gray-200 p-6 shadow-sm"> | |
| <div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center mb-3"> | |
| <i data-lucide="book-open" class="w-5 h-5 text-blue-600"></i> | |
| </div> | |
| <h4 class="font-semibold text-gray-900 mb-1">Documentation</h4> | |
| <p class="text-sm text-gray-500">Learn about this feature</p> | |
| </div> | |
| <div class="bg-white rounded-xl border border-gray-200 p-6 shadow-sm"> | |
| <div class="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center mb-3"> | |
| <i data-lucide="video" class="w-5 h-5 text-green-600"></i> | |
| </div> | |
| <h4 class="font-semibold text-gray-900 mb-1">Video Tutorial</h4> | |
| <p class="text-sm text-gray-500">Watch setup guide</p> | |
| </div> | |
| <div class="bg-white rounded-xl border border-gray-200 p-6 shadow-sm"> | |
| <div class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center mb-3"> | |
| <i data-lucide="message-circle" class="w-5 h-5 text-purple-600"></i> | |
| </div> | |
| <h4 class="font-semibold text-gray-900 mb-1">Support</h4> | |
| <p class="text-sm text-gray-500">Chat with our team</p> | |
| </div> | |
| </div> | |
| </div> | |
| ` | |
| } | |
| }; | |
| // Initialize | |
| document.addEventListener('DOMContentLoaded', () => { | |
| loadPage('org-business'); | |
| initializeMenus(); | |
| lucide.createIcons(); | |
| }); | |
| // Toggle Menu | |
| function toggleMenu(menuId) { | |
| const submenu = document.getElementById(`submenu-${menuId}`); | |
| const chevron = document.getElementById(`chevron-${menuId}`); | |
| if (submenu.classList.contains('open')) { | |
| submenu.classList.remove('open'); | |
| chevron.classList.remove('rotate'); | |
| openMenus = openMenus.filter(id => id !== menuId); | |
| } else { | |
| submenu.classList.add('open'); | |
| chevron.classList.add('rotate'); | |
| openMenus.push(menuId); | |
| } | |
| } | |
| // Initialize Open Menus | |
| function initializeMenus() { | |
| openMenus.forEach(menuId => { | |
| const submenu = document.getElementById(`submenu-${menuId}`); | |
| const chevron = document.getElementById(`chevron-${menuId}`); | |
| if (submenu && chevron) { | |
| submenu.classList.add('open'); | |
| chevron.classList.add('rotate'); | |
| } | |
| }); | |
| } | |
| // Load Page | |
| function loadPage(pageId) { | |
| currentPage = pageId; | |
| // Update Active States | |
| document.querySelectorAll('.sidebar-item[data-page]').forEach(item => { | |
| item.classList.remove('active'); | |
| if (item.getAttribute('data-page') === pageId) { | |
| item.classList.add('active'); | |
| } | |
| }); | |
| // Get Content | |
| const pageData = pageContents[pageId] || pageContents['default']; | |
| // Update Title & Badge | |
| document.getElementById('page-title').textContent = pageData.title; | |
| document.getElementById('page-badge').textContent = pageData.badge; | |
| // Update Content | |
| document.getElementById('content-area').innerHTML = pageData.content; | |
| // Re-init icons | |
| lucide.createIcons(); | |
| // Close mobile menu if open | |
| if (window.innerWidth < 1024) { | |
| document.getElementById('sidebar').classList.add('-translate-x-full'); | |
| document.getElementById('mobile-overlay').classList.add('hidden'); | |
| } | |
| // Add to command history | |
| if (!commandHistory.includes(pageId)) { | |
| commandHistory.unshift(pageId); | |
| if (commandHistory.length > 5) commandHistory.pop(); | |
| } | |
| } | |
| // Mobile Menu Toggle | |
| function toggleMobileMenu() { | |
| const sidebar = document.getElementById('sidebar'); | |
| const overlay = document.getElementById('mobile-overlay'); | |
| if (sidebar.classList.contains('-translate-x-full')) { | |
| sidebar.classList.remove('-translate-x-full'); | |
| overlay.classList.remove('hidden'); | |
| } else { | |
| sidebar.classList.add('-translate-x-full'); | |
| overlay.classList.add('hidden'); | |
| } | |
| } | |
| // Command Palette | |
| function openCommandPalette() { | |
| const palette = document.getElementById('command-palette'); | |
| palette.classList.remove('hidden'); | |
| document.getElementById('command-input').focus(); | |
| renderCommands(commands); | |
| } | |
| function closeCommandPalette() { | |
| document.getElementById('command-palette').classList.add('hidden'); | |
| } | |
| function filterCommands(query) { | |
| const filtered = commands.filter(cmd => | |
| cmd.label.toLowerCase().includes(query.toLowerCase()) || | |
| cmd.category.toLowerCase().includes(query.toLowerCase()) | |
| ); | |
| renderCommands(filtered); | |
| } | |
| function renderCommands(commandList) { | |
| const container = document.getElementById('command-list'); | |
| if (commandList.length === 0) { | |
| container.innerHTML = ` | |
| <div class="p-8 text-center text-gray-500"> | |
| <i data-lucide="search-x" class="w-8 h-8 mx-auto mb-2 opacity-50"></i> | |
| <p class="text-sm">No commands found</p> | |
| </div> | |
| `; | |
| lucide.createIcons(); | |
| return; | |
| } | |
| // Group by category | |
| const grouped = commandList.reduce((acc, cmd) => { | |
| if (!acc[cmd.category]) acc[cmd.category] = []; | |
| acc[cmd.category].push(cmd); | |
| return acc; | |
| }, {}); | |
| let html = ''; | |
| for (const [category, items] of Object.entries(grouped)) { | |
| html += ` | |
| <div class="mb-2"> | |
| <p class="px-3 py-2 text-xs font-semibold text-gray-400 uppercase tracking-wider">${category}</p> | |
| ${items.map(cmd => ` | |
| <button onclick="executeCommand('${cmd.id}')" class="w-full flex items-center gap-3 px-3 py-2.5 rounded-lg hover:bg-gray-100 group transition-colors text-left"> | |
| <div class="w-8 h-8 rounded-lg bg-gray-100 flex items-center justify-center group-hover:bg-white group-hover:shadow-sm transition-all"> | |
| <i data-lucide="${cmd.icon}" class="w-4 h-4 text-gray-600"></i> | |
| </div> | |
| <div class="flex-1"> | |
| <p class="text-sm font-medium text-gray-900 group-hover:text-primary transition-colors">${cmd.label}</p> | |
| </div> | |
| <i data-lucide="arrow-right" class="w-4 h-4 text-gray-400 opacity-0 group-hover:opacity-100 transition-opacity"></i> | |
| </button> | |
| `).join('')} | |
| </div> | |
| `; | |
| } | |
| container.innerHTML = html; | |
| lucide.createIcons(); | |
| } | |
| function executeCommand(commandId) { | |
| closeCommandPalette(); | |
| loadPage(commandId); | |
| // Ensure parent menu is open | |
| const command = commands.find(c => c.id === commandId); | |
| if (command) { | |
| const menuMap = { | |
| 'Organization': 'org', | |
| 'Providers': 'providers', | |
| 'Scheduling': 'scheduling', | |
| 'Billing': 'billing', | |
| 'Communications': 'comms', | |
| 'Forms': 'forms', | |
| 'Compliance': 'compliance', | |
| 'AI & Automation': 'ai', | |
| 'Integrations': 'integrations', | |
| 'Analytics': 'analytics', | |
| 'Patient Experience': 'patient', | |
| 'Security': 'security', | |
| 'System': 'system', | |
| 'Enterprise': 'enterprise' | |
| }; | |
| const menuId = menuMap[command.category]; | |
| if (menuId && !openMenus.includes(menuId)) { | |
| toggleMenu(menuId); | |
| } | |
| } | |
| } | |
| // Keyboard Shortcuts | |
| document.addEventListener('keydown', (e) => { | |
| // Cmd/Ctrl + K | |
| if ((e.metaKey || e.ctrlKey) && e.key === 'k') { | |
| e.preventDefault(); | |
| openCommandPalette(); | |
| } | |
| // Escape | |
| if (e.key === 'Escape') { | |
| closeCommandPalette(); | |
| } | |
| }); |