import React, { useState, useEffect } from 'react'; import { X, Send, Mail, Building2, ChevronDown, ChevronUp } from 'lucide-react'; import { useCreateTenantInvitation } from '../../../hooks/usePlatform'; import { useSubscriptionPlans } from '../../../hooks/usePlatformSettings'; interface TenantInviteModalProps { isOpen: boolean; onClose: () => void; } // Default tier settings - used when no subscription plans are loaded const TIER_DEFAULTS: Record = { FREE: { max_users: 2, max_resources: 5, can_manage_oauth_credentials: false, can_accept_payments: false, can_use_custom_domain: false, can_white_label: false, can_api_access: false, can_add_video_conferencing: false, can_use_sms_reminders: false, can_use_masked_phone_numbers: false, can_use_plugins: true, can_use_tasks: true, can_create_plugins: false, can_use_webhooks: false, can_use_calendar_sync: false, can_export_data: false, can_require_2fa: false, }, STARTER: { max_users: 5, max_resources: 15, can_manage_oauth_credentials: false, can_accept_payments: true, can_use_custom_domain: false, can_white_label: false, can_api_access: false, can_add_video_conferencing: false, can_use_sms_reminders: false, can_use_masked_phone_numbers: false, can_use_plugins: true, can_use_tasks: true, can_create_plugins: false, can_use_webhooks: false, can_use_calendar_sync: false, can_export_data: false, can_require_2fa: false, }, PROFESSIONAL: { max_users: 15, max_resources: 50, can_manage_oauth_credentials: false, can_accept_payments: true, can_use_custom_domain: true, can_white_label: false, can_api_access: true, can_add_video_conferencing: true, can_use_sms_reminders: true, can_use_masked_phone_numbers: false, can_use_plugins: true, can_use_tasks: true, can_create_plugins: false, can_use_webhooks: true, can_use_calendar_sync: true, can_export_data: true, can_require_2fa: false, }, ENTERPRISE: { max_users: -1, // unlimited max_resources: -1, // unlimited can_manage_oauth_credentials: true, can_accept_payments: true, can_use_custom_domain: true, can_white_label: true, can_api_access: true, can_add_video_conferencing: true, can_use_sms_reminders: true, can_use_masked_phone_numbers: true, can_use_plugins: true, can_use_tasks: true, can_create_plugins: true, can_use_webhooks: true, can_use_calendar_sync: true, can_export_data: true, can_require_2fa: true, }, }; const TenantInviteModal: React.FC = ({ isOpen, onClose }) => { const createInvitationMutation = useCreateTenantInvitation(); const { data: subscriptionPlans } = useSubscriptionPlans(); const [inviteForm, setInviteForm] = useState({ email: '', suggested_business_name: '', subscription_tier: 'PROFESSIONAL' as 'FREE' | 'STARTER' | 'PROFESSIONAL' | 'ENTERPRISE', use_custom_limits: false, // Limits max_users: 15, max_resources: 50, // Permissions can_manage_oauth_credentials: false, can_accept_payments: true, can_use_custom_domain: true, can_white_label: false, can_api_access: true, can_add_video_conferencing: true, can_use_sms_reminders: true, can_use_masked_phone_numbers: false, can_use_plugins: true, can_use_tasks: true, can_create_plugins: false, can_use_webhooks: true, can_use_calendar_sync: true, can_export_data: true, can_require_2fa: false, personal_message: '', }); const [inviteError, setInviteError] = useState(null); const [inviteSuccess, setInviteSuccess] = useState(false); // Get tier defaults from subscription plans or fallback to static defaults const getTierDefaults = (tier: string) => { // Try to find matching subscription plan if (subscriptionPlans) { const tierNameMap: Record = { 'FREE': 'Free', 'STARTER': 'Starter', 'PROFESSIONAL': 'Professional', 'ENTERPRISE': 'Enterprise', }; const plan = subscriptionPlans.find(p => p.name === tierNameMap[tier] || p.name === tier ); if (plan) { const staticDefaults = TIER_DEFAULTS[tier] || TIER_DEFAULTS.FREE; return { max_users: plan.limits?.max_users ?? staticDefaults.max_users, max_resources: plan.limits?.max_resources ?? staticDefaults.max_resources, 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, can_add_video_conferencing: plan.permissions?.video_conferencing ?? staticDefaults.can_add_video_conferencing, can_use_sms_reminders: plan.permissions?.sms_reminders ?? staticDefaults.can_use_sms_reminders, can_use_masked_phone_numbers: plan.permissions?.masked_calling ?? staticDefaults.can_use_masked_phone_numbers, can_use_plugins: plan.permissions?.plugins ?? staticDefaults.can_use_plugins, can_use_tasks: plan.permissions?.tasks ?? staticDefaults.can_use_tasks, can_create_plugins: plan.permissions?.can_create_plugins ?? staticDefaults.can_create_plugins, can_use_webhooks: plan.permissions?.webhooks ?? staticDefaults.can_use_webhooks, can_use_calendar_sync: plan.permissions?.calendar_sync ?? staticDefaults.can_use_calendar_sync, can_export_data: plan.permissions?.export_data ?? staticDefaults.can_export_data, can_require_2fa: plan.permissions?.two_factor_auth ?? staticDefaults.can_require_2fa, }; } } // Fallback to static defaults return TIER_DEFAULTS[tier] || TIER_DEFAULTS.FREE; }; // Handle subscription tier change - auto-update limits and permissions const handleTierChange = (newTier: string) => { const defaults = getTierDefaults(newTier); setInviteForm(prev => ({ ...prev, subscription_tier: newTier as any, ...defaults, })); }; // Initialize defaults when modal opens or subscription plans load useEffect(() => { if (isOpen) { const defaults = getTierDefaults(inviteForm.subscription_tier); setInviteForm(prev => ({ ...prev, ...defaults, })); } }, [isOpen, subscriptionPlans]); const resetForm = () => { const defaults = getTierDefaults('PROFESSIONAL'); setInviteForm({ email: '', suggested_business_name: '', subscription_tier: 'PROFESSIONAL', use_custom_limits: false, ...defaults, personal_message: '', }); setInviteError(null); setInviteSuccess(false); }; const handleClose = () => { resetForm(); onClose(); }; const handleInviteSend = () => { setInviteError(null); setInviteSuccess(false); // Validation if (!inviteForm.email.trim()) { setInviteError('Email address is required'); return; } if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(inviteForm.email)) { setInviteError('Please enter a valid email address'); return; } // Build invitation data const data: any = { email: inviteForm.email, subscription_tier: inviteForm.subscription_tier, }; if (inviteForm.suggested_business_name.trim()) { data.suggested_business_name = inviteForm.suggested_business_name.trim(); } // If using custom limits, include all the overrides if (inviteForm.use_custom_limits) { data.custom_max_users = inviteForm.max_users; data.custom_max_resources = inviteForm.max_resources; data.permissions = { can_manage_oauth_credentials: inviteForm.can_manage_oauth_credentials, can_accept_payments: inviteForm.can_accept_payments, can_use_custom_domain: inviteForm.can_use_custom_domain, can_white_label: inviteForm.can_white_label, can_api_access: inviteForm.can_api_access, }; data.limits = { can_add_video_conferencing: inviteForm.can_add_video_conferencing, can_use_sms_reminders: inviteForm.can_use_sms_reminders, can_use_masked_phone_numbers: inviteForm.can_use_masked_phone_numbers, can_use_plugins: inviteForm.can_use_plugins, can_use_tasks: inviteForm.can_use_tasks, can_create_plugins: inviteForm.can_create_plugins, can_use_webhooks: inviteForm.can_use_webhooks, can_use_calendar_sync: inviteForm.can_use_calendar_sync, can_export_data: inviteForm.can_export_data, can_require_2fa: inviteForm.can_require_2fa, }; } if (inviteForm.personal_message.trim()) { data.personal_message = inviteForm.personal_message.trim(); } createInvitationMutation.mutate(data, { onSuccess: () => { setInviteSuccess(true); setTimeout(() => { handleClose(); }, 2000); }, onError: (error: any) => { setInviteError(error.response?.data?.detail || error.message || 'Failed to send invitation'); }, }); }; if (!isOpen) return null; return (
{/* Modal Header */}

Invite New Tenant

Send an invitation to create a new business

{/* Modal Body */}
{inviteError && (

{inviteError}

)} {inviteSuccess && (

Invitation sent successfully!

)} {/* Email */}
setInviteForm({ ...inviteForm, email: e.target.value })} className="w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white" placeholder="owner@business.com" />
{/* Suggested Business Name */}
setInviteForm({ ...inviteForm, suggested_business_name: e.target.value })} className="w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white" placeholder="Owner can change this during onboarding" />
{/* Subscription Tier */}

Tier defaults are loaded from platform subscription settings

{/* Override Tier Limits Toggle */}
{/* Sliding Custom Limits Panel */}
{/* Limits Configuration */}

Limits Configuration

Use -1 for unlimited

setInviteForm({ ...inviteForm, max_users: 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" />
setInviteForm({ ...inviteForm, max_resources: 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" />
{/* Payments & Revenue */}

Payments & Revenue

{/* Communication */}

Communication

{/* Customization */}

Customization

{/* Plugins & Automation */}

Plugins & Automation

{/* Advanced Features */}

Advanced Features

{/* Enterprise */}

Enterprise

{/* Personal Message */}