thors1's picture
Initial DeepSite commit
88aa948 verified
// 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();
}
});