feat: Dashboard redesign, plan permissions, and help docs improvements
Major updates including: - Customizable dashboard with drag-and-drop widget grid layout - Plan-based feature locking for plugins and tasks - Comprehensive help documentation updates across all pages - Plugin seeding in deployment process for all tenants - Permission synchronization system for subscription plans - QuotaOverageModal component and enhanced UX flows 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -69,38 +69,29 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
// Limits
|
||||
max_users: 5,
|
||||
max_resources: 10,
|
||||
max_services: 0,
|
||||
max_appointments: 0,
|
||||
max_email_templates: 0,
|
||||
max_automated_tasks: 0,
|
||||
// Platform Permissions
|
||||
// Platform Permissions (flat, matching backend model)
|
||||
can_manage_oauth_credentials: false,
|
||||
can_accept_payments: false,
|
||||
can_use_custom_domain: false,
|
||||
can_white_label: false,
|
||||
can_api_access: false,
|
||||
// Extended Permissions
|
||||
permissions: {
|
||||
// Payments & Revenue
|
||||
can_process_refunds: false,
|
||||
can_create_packages: false,
|
||||
// Communication
|
||||
sms_reminders: false,
|
||||
can_use_masked_phone_numbers: false,
|
||||
can_use_email_templates: false,
|
||||
// Customization
|
||||
can_customize_booking_page: false,
|
||||
// Advanced Features
|
||||
advanced_reporting: false,
|
||||
can_create_plugins: false,
|
||||
can_export_data: false,
|
||||
can_use_webhooks: false,
|
||||
calendar_sync: false,
|
||||
// Support & Enterprise
|
||||
priority_support: false,
|
||||
dedicated_support: false,
|
||||
sso_enabled: false,
|
||||
},
|
||||
// Feature permissions (flat, matching backend model)
|
||||
can_add_video_conferencing: false,
|
||||
can_connect_to_api: false,
|
||||
can_book_repeated_events: true,
|
||||
can_require_2fa: false,
|
||||
can_download_logs: false,
|
||||
can_delete_data: false,
|
||||
can_use_sms_reminders: false,
|
||||
can_use_masked_phone_numbers: false,
|
||||
can_use_pos: false,
|
||||
can_use_mobile_app: false,
|
||||
can_export_data: false,
|
||||
can_use_plugins: true,
|
||||
can_use_tasks: true,
|
||||
can_create_plugins: false,
|
||||
can_use_webhooks: false,
|
||||
can_use_calendar_sync: false,
|
||||
});
|
||||
|
||||
// Get tier defaults from subscription plans or fallback to static defaults
|
||||
@@ -122,33 +113,29 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
// Limits
|
||||
max_users: plan.limits?.max_users ?? staticDefaults.max_users,
|
||||
max_resources: plan.limits?.max_resources ?? staticDefaults.max_resources,
|
||||
max_services: plan.limits?.max_services ?? 0,
|
||||
max_appointments: plan.limits?.max_appointments ?? 0,
|
||||
max_email_templates: plan.limits?.max_email_templates ?? 0,
|
||||
max_automated_tasks: plan.limits?.max_automated_tasks ?? 0,
|
||||
// Platform Permissions
|
||||
can_manage_oauth_credentials: plan.permissions?.can_manage_oauth_credentials ?? staticDefaults.can_manage_oauth_credentials,
|
||||
can_accept_payments: plan.permissions?.can_accept_payments ?? staticDefaults.can_accept_payments,
|
||||
can_use_custom_domain: plan.permissions?.can_use_custom_domain ?? staticDefaults.can_use_custom_domain,
|
||||
can_white_label: plan.permissions?.can_white_label ?? staticDefaults.can_white_label,
|
||||
can_api_access: plan.permissions?.can_api_access ?? staticDefaults.can_api_access,
|
||||
// Extended Permissions
|
||||
permissions: {
|
||||
can_process_refunds: plan.permissions?.can_process_refunds ?? false,
|
||||
can_create_packages: plan.permissions?.can_create_packages ?? false,
|
||||
sms_reminders: plan.permissions?.sms_reminders ?? false,
|
||||
can_use_masked_phone_numbers: plan.permissions?.can_use_masked_phone_numbers ?? false,
|
||||
can_use_email_templates: plan.permissions?.can_use_email_templates ?? false,
|
||||
can_customize_booking_page: plan.permissions?.can_customize_booking_page ?? false,
|
||||
advanced_reporting: plan.permissions?.advanced_reporting ?? false,
|
||||
can_create_plugins: plan.permissions?.can_create_plugins ?? false,
|
||||
can_export_data: plan.permissions?.can_export_data ?? false,
|
||||
can_use_webhooks: plan.permissions?.can_use_webhooks ?? false,
|
||||
calendar_sync: plan.permissions?.calendar_sync ?? false,
|
||||
priority_support: plan.permissions?.priority_support ?? false,
|
||||
dedicated_support: plan.permissions?.dedicated_support ?? false,
|
||||
sso_enabled: plan.permissions?.sso_enabled ?? false,
|
||||
},
|
||||
// Feature permissions (flat, matching backend model)
|
||||
can_add_video_conferencing: plan.permissions?.video_conferencing ?? false,
|
||||
can_connect_to_api: plan.permissions?.can_api_access ?? false,
|
||||
can_book_repeated_events: true,
|
||||
can_require_2fa: false,
|
||||
can_download_logs: false,
|
||||
can_delete_data: false,
|
||||
can_use_sms_reminders: plan.permissions?.sms_reminders ?? false,
|
||||
can_use_masked_phone_numbers: plan.permissions?.masked_calling ?? false,
|
||||
can_use_pos: false,
|
||||
can_use_mobile_app: false,
|
||||
can_export_data: plan.permissions?.export_data ?? false,
|
||||
can_use_plugins: plan.permissions?.plugins ?? true,
|
||||
can_use_tasks: plan.permissions?.tasks ?? true,
|
||||
can_create_plugins: plan.permissions?.can_create_plugins ?? false,
|
||||
can_use_webhooks: plan.permissions?.webhooks ?? false,
|
||||
can_use_calendar_sync: plan.permissions?.calendar_sync ?? false,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -156,26 +143,22 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
const staticDefaults = TIER_DEFAULTS[tier] || TIER_DEFAULTS.FREE;
|
||||
return {
|
||||
...staticDefaults,
|
||||
max_services: 0,
|
||||
max_appointments: 0,
|
||||
max_email_templates: 0,
|
||||
max_automated_tasks: 0,
|
||||
permissions: {
|
||||
can_process_refunds: false,
|
||||
can_create_packages: false,
|
||||
sms_reminders: false,
|
||||
can_use_masked_phone_numbers: false,
|
||||
can_use_email_templates: false,
|
||||
can_customize_booking_page: false,
|
||||
advanced_reporting: false,
|
||||
can_create_plugins: false,
|
||||
can_export_data: false,
|
||||
can_use_webhooks: false,
|
||||
calendar_sync: false,
|
||||
priority_support: false,
|
||||
dedicated_support: false,
|
||||
sso_enabled: false,
|
||||
},
|
||||
can_add_video_conferencing: false,
|
||||
can_connect_to_api: staticDefaults.can_api_access,
|
||||
can_book_repeated_events: true,
|
||||
can_require_2fa: false,
|
||||
can_download_logs: false,
|
||||
can_delete_data: false,
|
||||
can_use_sms_reminders: false,
|
||||
can_use_masked_phone_numbers: false,
|
||||
can_use_pos: false,
|
||||
can_use_mobile_app: false,
|
||||
can_export_data: false,
|
||||
can_use_plugins: true,
|
||||
can_use_tasks: true,
|
||||
can_create_plugins: false,
|
||||
can_use_webhooks: false,
|
||||
can_use_calendar_sync: false,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -201,6 +184,7 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
// Update form when business changes
|
||||
useEffect(() => {
|
||||
if (business) {
|
||||
const b = business as any;
|
||||
setEditForm({
|
||||
name: business.name,
|
||||
is_active: business.is_active,
|
||||
@@ -208,47 +192,33 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
// Limits
|
||||
max_users: business.max_users || 5,
|
||||
max_resources: business.max_resources || 10,
|
||||
max_services: (business as any).max_services || 0,
|
||||
max_appointments: (business as any).max_appointments || 0,
|
||||
max_email_templates: (business as any).max_email_templates || 0,
|
||||
max_automated_tasks: (business as any).max_automated_tasks || 0,
|
||||
// Platform Permissions
|
||||
// Platform Permissions (flat, matching backend)
|
||||
can_manage_oauth_credentials: business.can_manage_oauth_credentials || false,
|
||||
can_accept_payments: business.can_accept_payments || false,
|
||||
can_use_custom_domain: business.can_use_custom_domain || false,
|
||||
can_white_label: business.can_white_label || false,
|
||||
can_api_access: business.can_api_access || false,
|
||||
// Extended Permissions
|
||||
permissions: {
|
||||
can_process_refunds: (business as any).permissions?.can_process_refunds || false,
|
||||
can_create_packages: (business as any).permissions?.can_create_packages || false,
|
||||
sms_reminders: (business as any).permissions?.sms_reminders || false,
|
||||
can_use_masked_phone_numbers: (business as any).permissions?.can_use_masked_phone_numbers || false,
|
||||
can_use_email_templates: (business as any).permissions?.can_use_email_templates || false,
|
||||
can_customize_booking_page: (business as any).permissions?.can_customize_booking_page || false,
|
||||
advanced_reporting: (business as any).permissions?.advanced_reporting || false,
|
||||
can_create_plugins: (business as any).permissions?.can_create_plugins || false,
|
||||
can_export_data: (business as any).permissions?.can_export_data || false,
|
||||
can_use_webhooks: (business as any).permissions?.can_use_webhooks || false,
|
||||
calendar_sync: (business as any).permissions?.calendar_sync || false,
|
||||
priority_support: (business as any).permissions?.priority_support || false,
|
||||
dedicated_support: (business as any).permissions?.dedicated_support || false,
|
||||
sso_enabled: (business as any).permissions?.sso_enabled || false,
|
||||
},
|
||||
can_accept_payments: b.can_accept_payments || false,
|
||||
can_use_custom_domain: b.can_use_custom_domain || false,
|
||||
can_white_label: b.can_white_label || false,
|
||||
can_api_access: b.can_api_access || false,
|
||||
// Feature permissions (flat, matching backend)
|
||||
can_add_video_conferencing: b.can_add_video_conferencing || false,
|
||||
can_connect_to_api: b.can_connect_to_api || false,
|
||||
can_book_repeated_events: b.can_book_repeated_events ?? true,
|
||||
can_require_2fa: b.can_require_2fa || false,
|
||||
can_download_logs: b.can_download_logs || false,
|
||||
can_delete_data: b.can_delete_data || false,
|
||||
can_use_sms_reminders: b.can_use_sms_reminders || false,
|
||||
can_use_masked_phone_numbers: b.can_use_masked_phone_numbers || false,
|
||||
can_use_pos: b.can_use_pos || false,
|
||||
can_use_mobile_app: b.can_use_mobile_app || false,
|
||||
can_export_data: b.can_export_data || false,
|
||||
can_use_plugins: b.can_use_plugins ?? true,
|
||||
can_use_tasks: b.can_use_tasks ?? true,
|
||||
can_create_plugins: b.can_create_plugins || false,
|
||||
can_use_webhooks: b.can_use_webhooks || false,
|
||||
can_use_calendar_sync: b.can_use_calendar_sync || false,
|
||||
});
|
||||
}
|
||||
}, [business]);
|
||||
|
||||
// Helper for permission changes
|
||||
const handlePermissionChange = (key: string, value: boolean) => {
|
||||
setEditForm(prev => ({
|
||||
...prev,
|
||||
permissions: {
|
||||
...prev.permissions,
|
||||
[key]: value,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
const handleEditSave = () => {
|
||||
if (!business) return;
|
||||
@@ -357,7 +327,7 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
Use -1 for unlimited. These limits control what this business can create.
|
||||
</p>
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Max Users
|
||||
@@ -382,54 +352,6 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Max Services
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
min="-1"
|
||||
value={editForm.max_services}
|
||||
onChange={(e) => setEditForm({ ...editForm, max_services: parseInt(e.target.value) || 0 })}
|
||||
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Max Appointments / Month
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
min="-1"
|
||||
value={editForm.max_appointments}
|
||||
onChange={(e) => setEditForm({ ...editForm, max_appointments: parseInt(e.target.value) || 0 })}
|
||||
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Max Email Templates
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
min="-1"
|
||||
value={editForm.max_email_templates}
|
||||
onChange={(e) => setEditForm({ ...editForm, max_email_templates: parseInt(e.target.value) || 0 })}
|
||||
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Max Automated Tasks
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
min="-1"
|
||||
value={editForm.max_automated_tasks}
|
||||
onChange={(e) => setEditForm({ ...editForm, max_automated_tasks: parseInt(e.target.value) || 0 })}
|
||||
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -456,24 +378,6 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Online Payments</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.can_process_refunds}
|
||||
onChange={(e) => handlePermissionChange('can_process_refunds', e.target.checked)}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Process Refunds</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.can_create_packages}
|
||||
onChange={(e) => handlePermissionChange('can_create_packages', e.target.checked)}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Service Packages</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -484,8 +388,8 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.sms_reminders}
|
||||
onChange={(e) => handlePermissionChange('sms_reminders', e.target.checked)}
|
||||
checked={editForm.can_use_sms_reminders}
|
||||
onChange={(e) => setEditForm({ ...editForm, can_use_sms_reminders: e.target.checked })}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">SMS Reminders</span>
|
||||
@@ -493,21 +397,12 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.can_use_masked_phone_numbers}
|
||||
onChange={(e) => handlePermissionChange('can_use_masked_phone_numbers', e.target.checked)}
|
||||
checked={editForm.can_use_masked_phone_numbers}
|
||||
onChange={(e) => setEditForm({ ...editForm, can_use_masked_phone_numbers: e.target.checked })}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Masked Calling</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.can_use_email_templates}
|
||||
onChange={(e) => handlePermissionChange('can_use_email_templates', e.target.checked)}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Email Templates</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -515,15 +410,6 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
<div>
|
||||
<h4 className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2">Customization</h4>
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.can_customize_booking_page}
|
||||
onChange={(e) => handlePermissionChange('can_customize_booking_page', e.target.checked)}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Custom Booking Page</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
@@ -545,19 +431,59 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Advanced Features */}
|
||||
{/* Plugins & Automation */}
|
||||
<div>
|
||||
<h4 className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2">Advanced Features</h4>
|
||||
<h4 className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2">Plugins & Automation</h4>
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.advanced_reporting}
|
||||
onChange={(e) => handlePermissionChange('advanced_reporting', e.target.checked)}
|
||||
checked={editForm.can_use_plugins}
|
||||
onChange={(e) => {
|
||||
const checked = e.target.checked;
|
||||
setEditForm(prev => ({
|
||||
...prev,
|
||||
can_use_plugins: checked,
|
||||
// If disabling plugins, also disable tasks and create plugins
|
||||
...(checked ? {} : { can_use_tasks: false, can_create_plugins: false })
|
||||
}));
|
||||
}}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Advanced Analytics</span>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Use Plugins</span>
|
||||
</label>
|
||||
<label className={`flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg ${editForm.can_use_plugins ? 'hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer' : 'opacity-50 cursor-not-allowed'}`}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.can_use_tasks}
|
||||
onChange={(e) => setEditForm({ ...editForm, can_use_tasks: e.target.checked })}
|
||||
disabled={!editForm.can_use_plugins}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 disabled:opacity-50"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Scheduled Tasks</span>
|
||||
</label>
|
||||
<label className={`flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg ${editForm.can_use_plugins ? 'hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer' : 'opacity-50 cursor-not-allowed'}`}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.can_create_plugins}
|
||||
onChange={(e) => setEditForm({ ...editForm, can_create_plugins: e.target.checked })}
|
||||
disabled={!editForm.can_use_plugins}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500 disabled:opacity-50"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Create Plugins</span>
|
||||
</label>
|
||||
</div>
|
||||
{!editForm.can_use_plugins && (
|
||||
<p className="text-xs text-amber-600 dark:text-amber-400 mt-2">
|
||||
Enable "Use Plugins" to allow Scheduled Tasks and Create Plugins
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Advanced Features */}
|
||||
<div>
|
||||
<h4 className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2">Advanced Features</h4>
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
@@ -570,26 +496,8 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.can_create_plugins}
|
||||
onChange={(e) => handlePermissionChange('can_create_plugins', e.target.checked)}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Create Plugins</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.can_export_data}
|
||||
onChange={(e) => handlePermissionChange('can_export_data', e.target.checked)}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Data Export</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.can_use_webhooks}
|
||||
onChange={(e) => handlePermissionChange('can_use_webhooks', e.target.checked)}
|
||||
checked={editForm.can_use_webhooks}
|
||||
onChange={(e) => setEditForm({ ...editForm, can_use_webhooks: e.target.checked })}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Webhooks</span>
|
||||
@@ -597,18 +505,36 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.calendar_sync}
|
||||
onChange={(e) => handlePermissionChange('calendar_sync', e.target.checked)}
|
||||
checked={editForm.can_use_calendar_sync}
|
||||
onChange={(e) => setEditForm({ ...editForm, can_use_calendar_sync: e.target.checked })}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Calendar Sync</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.can_export_data}
|
||||
onChange={(e) => setEditForm({ ...editForm, can_export_data: e.target.checked })}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Data Export</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.can_add_video_conferencing}
|
||||
onChange={(e) => setEditForm({ ...editForm, can_add_video_conferencing: e.target.checked })}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Video Conferencing</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Support & Enterprise */}
|
||||
{/* Enterprise */}
|
||||
<div>
|
||||
<h4 className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2">Support & Enterprise</h4>
|
||||
<h4 className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider mb-2">Enterprise</h4>
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
@@ -622,29 +548,11 @@ const BusinessEditModal: React.FC<BusinessEditModalProps> = ({ business, isOpen,
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.priority_support}
|
||||
onChange={(e) => handlePermissionChange('priority_support', e.target.checked)}
|
||||
checked={editForm.can_require_2fa}
|
||||
onChange={(e) => setEditForm({ ...editForm, can_require_2fa: e.target.checked })}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Priority Support</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.dedicated_support}
|
||||
onChange={(e) => handlePermissionChange('dedicated_support', e.target.checked)}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Dedicated Support</span>
|
||||
</label>
|
||||
<label className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700/50 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editForm.permissions.sso_enabled}
|
||||
onChange={(e) => handlePermissionChange('sso_enabled', e.target.checked)}
|
||||
className="rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">SSO / SAML</span>
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">Require 2FA</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user