From d25c578e59c0657165d9052301ebdc52b004c12e Mon Sep 17 00:00:00 2001 From: poduck Date: Fri, 12 Dec 2025 03:15:39 -0500 Subject: [PATCH] Remove Tiers & Pricing tab from Platform Settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Billing management is now handled on the dedicated Billing page. Removed ~1050 lines of dead code including TiersSettingsTab, PlanRow, and PlanModal components. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../src/pages/platform/PlatformSettings.tsx | 1051 +---------------- 1 file changed, 1 insertion(+), 1050 deletions(-) diff --git a/frontend/src/pages/platform/PlatformSettings.tsx b/frontend/src/pages/platform/PlatformSettings.tsx index b3494ad..d49cb2a 100644 --- a/frontend/src/pages/platform/PlatformSettings.tsx +++ b/frontend/src/pages/platform/PlatformSettings.tsx @@ -14,13 +14,6 @@ import { Loader2, Eye, EyeOff, - Layers, - Plus, - Pencil, - Trash2, - X, - DollarSign, - Check, Lock, Users, ExternalLink, @@ -33,15 +26,13 @@ import { useValidateStripeKeys, useUpdateGeneralSettings, } from '../../hooks/usePlatformSettings'; -import BillingPlansTab from './components/BillingPlansTab'; import { usePlatformOAuthSettings, useUpdatePlatformOAuthSettings, } from '../../hooks/usePlatformOAuth'; import { Link } from 'react-router-dom'; -import FeaturesPermissionsEditor, { getPermissionKey, PERMISSION_DEFINITIONS } from '../../components/platform/FeaturesPermissionsEditor'; -type TabType = 'general' | 'stripe' | 'tiers' | 'oauth'; +type TabType = 'general' | 'stripe' | 'oauth'; const PlatformSettings: React.FC = () => { const { t } = useTranslation(); @@ -50,7 +41,6 @@ const PlatformSettings: React.FC = () => { const tabs: { id: TabType; label: string; icon: React.ElementType }[] = [ { id: 'general', label: t('platform.settings.general', 'General'), icon: Settings }, { id: 'stripe', label: 'Stripe', icon: CreditCard }, - { id: 'tiers', label: t('platform.settings.tiersPricing'), icon: Layers }, { id: 'oauth', label: t('platform.settings.oauthProviders'), icon: Users }, ]; @@ -95,7 +85,6 @@ const PlatformSettings: React.FC = () => { {/* Tab Content */} {activeTab === 'general' && } {activeTab === 'stripe' && } - {activeTab === 'tiers' && } {activeTab === 'oauth' && } ); @@ -516,1044 +505,6 @@ const StripeSettingsTab: React.FC = () => { ); }; - -const TiersSettingsTab: React.FC = () => { - const { t } = useTranslation(); - const { data: plans, isLoading, error } = useSubscriptionPlans(); - const createPlanMutation = useCreateSubscriptionPlan(); - const updatePlanMutation = useUpdateSubscriptionPlan(); - const deletePlanMutation = useDeleteSubscriptionPlan(); - const syncMutation = useSyncPlansWithStripe(); - const syncTenantsMutation = useSyncPlanToTenants(); - - const [showModal, setShowModal] = useState(false); - const [editingPlan, setEditingPlan] = useState(null); - const [showSyncConfirmModal, setShowSyncConfirmModal] = useState(false); - const [savedPlanForSync, setSavedPlanForSync] = useState(null); - - const handleCreatePlan = () => { - setEditingPlan(null); - setShowModal(true); - }; - - const handleEditPlan = (plan: SubscriptionPlan) => { - setEditingPlan(plan); - setShowModal(true); - }; - - const handleDeletePlan = async (plan: SubscriptionPlan) => { - if (confirm(`Are you sure you want to deactivate the "${plan.name}" plan?`)) { - await deletePlanMutation.mutateAsync(plan.id); - } - }; - - const handleSavePlan = async (data: SubscriptionPlanCreate) => { - if (editingPlan) { - await updatePlanMutation.mutateAsync({ id: editingPlan.id, ...data }); - // After updating an existing plan, ask if they want to sync to tenants - setSavedPlanForSync(editingPlan); - setShowSyncConfirmModal(true); - } else { - await createPlanMutation.mutateAsync(data); - } - setShowModal(false); - setEditingPlan(null); - }; - - const handleSyncConfirm = async () => { - if (savedPlanForSync) { - await syncTenantsMutation.mutateAsync(savedPlanForSync.id); - } - setShowSyncConfirmModal(false); - setSavedPlanForSync(null); - }; - - const handleSyncCancel = () => { - setShowSyncConfirmModal(false); - setSavedPlanForSync(null); - }; - - if (isLoading) { - return ( -
- -
- ); - } - - if (error) { - return ( -
-
- - Failed to load subscription plans -
-
- ); - } - - const basePlans = plans?.filter((p) => p.plan_type === 'base') || []; - const addonPlans = plans?.filter((p) => p.plan_type === 'addon') || []; - - return ( -
- {/* Header */} -
-
-

- Subscription Plans -

-

- Configure pricing tiers and add-ons for businesses -

-
-
- - -
-
- - {/* Base Plans */} -
-
-

{t('platform.settings.baseTiers')}

-
-
- {basePlans.length === 0 ? ( -
- No base tiers configured. Click "Add Plan" to create one. -
- ) : ( - basePlans.map((plan) => ( - handleEditPlan(plan)} - onDelete={() => handleDeletePlan(plan)} - /> - )) - )} -
-
- - {/* Add-on Plans */} -
-
-

{t('platform.settings.addOns')}

-
-
- {addonPlans.length === 0 ? ( -
- No add-ons configured. -
- ) : ( - addonPlans.map((plan) => ( - handleEditPlan(plan)} - onDelete={() => handleDeletePlan(plan)} - /> - )) - )} -
-
- - {/* Plan Modal */} - {showModal && ( - { - setShowModal(false); - setEditingPlan(null); - }} - isLoading={createPlanMutation.isPending || updatePlanMutation.isPending} - /> - )} - - {/* Sync Confirmation Modal */} - {showSyncConfirmModal && savedPlanForSync && ( -
-
-
-

- Update All Tenants? -

-

- Do you want to sync the updated settings to all tenants currently on the "{savedPlanForSync.name}" plan? -

-

- This will update permissions and limits for all businesses on this tier. -

-
-
- - -
-
-
- )} -
- ); -}; - -interface PlanRowProps { - plan: SubscriptionPlan; - onEdit: () => void; - onDelete: () => void; -} - -const PlanRow: React.FC = ({ plan, onEdit, onDelete }) => { - return ( -
-
-
-

{plan.name}

- {!plan.is_active && ( - - Inactive - - )} - {!plan.is_public && plan.is_active && ( - - Hidden - - )} - {plan.is_most_popular && ( - - Popular - - )} - {!plan.show_price && ( - - Price Hidden - - )} -
-

{plan.description}

-
- {plan.price_monthly && ( - - - {parseFloat(plan.price_monthly).toFixed(2)}/mo - - )} - {plan.features.length > 0 && ( - - {plan.features.length} features - - )} - {parseFloat(plan.transaction_fee_percent) > 0 && ( - - {plan.transaction_fee_percent}% fee - - )} -
-
-
- - -
-
- ); -}; - -interface PlanModalProps { - plan: SubscriptionPlan | null; - onSave: (data: SubscriptionPlanCreate) => void; - onClose: () => void; - isLoading: boolean; -} - -const PlanModal: React.FC = ({ plan, onSave, onClose, isLoading }) => { - const [formData, setFormData] = useState({ - name: plan?.name || '', - description: plan?.description || '', - plan_type: plan?.plan_type || 'base', - price_monthly: plan?.price_monthly ? parseFloat(plan.price_monthly) : undefined, - price_yearly: plan?.price_yearly ? parseFloat(plan.price_yearly) : undefined, - features: plan?.features || [], - limits: plan?.limits || { - max_users: 5, - max_resources: 10, - max_appointments: 100, - max_automated_tasks: 5, - }, - permissions: plan?.permissions || { - can_accept_payments: false, - sms_reminders: false, - advanced_reporting: false, - priority_support: false, - can_use_custom_domain: false, - can_use_plugins: false, - can_use_tasks: false, - can_create_plugins: false, - can_white_label: false, - can_api_access: false, - can_use_masked_phone_numbers: false, - }, - // Default transaction fees: Stripe charges 2.9% + $0.30, so we need to charge more - // Recommended: FREE 5%+50¢, STARTER 4%+40¢, PROFESSIONAL 3.5%+35¢, ENTERPRISE 3%+30¢ - transaction_fee_percent: plan?.transaction_fee_percent - ? parseFloat(plan.transaction_fee_percent) - : 4.0, // Default 4% for new plans - transaction_fee_fixed: plan?.transaction_fee_fixed - ? parseFloat(plan.transaction_fee_fixed) - : 40, // Default 40 cents for new plans - // Communication pricing - sms_enabled: plan?.sms_enabled ?? false, - sms_price_per_message_cents: plan?.sms_price_per_message_cents ?? 3, - masked_calling_enabled: plan?.masked_calling_enabled ?? false, - masked_calling_price_per_minute_cents: plan?.masked_calling_price_per_minute_cents ?? 5, - proxy_number_enabled: plan?.proxy_number_enabled ?? false, - proxy_number_monthly_fee_cents: plan?.proxy_number_monthly_fee_cents ?? 200, - // Contracts feature - contracts_enabled: plan?.contracts_enabled ?? false, - // Default credit settings - default_auto_reload_enabled: plan?.default_auto_reload_enabled ?? false, - default_auto_reload_threshold_cents: plan?.default_auto_reload_threshold_cents ?? 1000, - default_auto_reload_amount_cents: plan?.default_auto_reload_amount_cents ?? 2500, - is_active: plan?.is_active ?? true, - is_public: plan?.is_public ?? true, - is_most_popular: plan?.is_most_popular ?? false, - show_price: plan?.show_price ?? true, - create_stripe_product: false, - stripe_product_id: plan?.stripe_product_id || '', - stripe_price_id: plan?.stripe_price_id || '', - }); - - const [newFeature, setNewFeature] = useState(''); - - const handleAddFeature = () => { - if (newFeature.trim()) { - setFormData((prev) => ({ - ...prev, - features: [...(prev.features || []), newFeature.trim()], - })); - setNewFeature(''); - } - }; - - const handleRemoveFeature = (index: number) => { - setFormData((prev) => ({ - ...prev, - features: prev.features?.filter((_, i) => i !== index) || [], - })); - }; - - const handleLimitChange = (key: string, value: string) => { - setFormData((prev) => ({ - ...prev, - limits: { - ...prev.limits, - [key]: parseInt(value) || 0, - }, - })); - }; - - const handlePermissionChange = (key: string, value: boolean) => { - setFormData((prev) => ({ - ...prev, - permissions: { - ...prev.permissions, - [key]: value, - }, - })); - }; - - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - onSave(formData); - }; - - return ( -
-
-
-

- {plan ? 'Edit Plan' : 'Create Plan'} -

- -
- -
- {/* Basic Info */} -
-

- Basic Information -

-
-
- - setFormData((prev) => ({ ...prev, name: e.target.value }))} - required - 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" - /> -
-
- - -
-
-
- -