Add TenantCustomTier system and fix BusinessEditModal feature loading
Backend: - Add TenantCustomTier model for per-tenant feature overrides - Update EntitlementService to check custom tier before plan features - Add custom_tier action on TenantViewSet (GET/PUT/DELETE) - Add Celery task for grace period management (30-day expiry) Frontend: - Add DynamicFeaturesEditor component for dynamic feature management - Fix BusinessEditModal to load features from plan defaults when no custom tier - Update limits (max_users, max_resources, etc.) to use featureValues - Remove outdated canonical feature check from FeaturePicker (removes warning icons) - Add useBillingPlans hook for accessing billing system data - Add custom tier API functions to platform.ts Features now follow consistent rules: - Load from plan defaults when no custom tier exists - Load from custom tier when one exists - Reset to plan defaults when plan changes - Save to custom tier on edit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import PricingTable from '../../components/marketing/PricingTable';
|
||||
import DynamicPricingCards from '../../components/marketing/DynamicPricingCards';
|
||||
import FeatureComparisonTable from '../../components/marketing/FeatureComparisonTable';
|
||||
import FAQAccordion from '../../components/marketing/FAQAccordion';
|
||||
import CTASection from '../../components/marketing/CTASection';
|
||||
|
||||
@@ -19,9 +20,25 @@ const PricingPage: React.FC = () => {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Pricing Table */}
|
||||
{/* Dynamic Pricing Cards */}
|
||||
<div className="pb-20">
|
||||
<PricingTable />
|
||||
<DynamicPricingCards />
|
||||
</div>
|
||||
|
||||
{/* Feature Comparison Table */}
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pb-20">
|
||||
<h2 className="text-3xl font-bold text-center text-gray-900 dark:text-white mb-4">
|
||||
{t('marketing.pricing.featureComparison.title', 'Compare Plans')}
|
||||
</h2>
|
||||
<p className="text-center text-gray-600 dark:text-gray-400 mb-12 max-w-2xl mx-auto">
|
||||
{t(
|
||||
'marketing.pricing.featureComparison.subtitle',
|
||||
'See exactly what you get with each plan'
|
||||
)}
|
||||
</p>
|
||||
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-sm border border-gray-200 dark:border-gray-700 p-6">
|
||||
<FeatureComparisonTable />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* FAQ Section */}
|
||||
@@ -29,24 +46,26 @@ const PricingPage: React.FC = () => {
|
||||
<h2 className="text-3xl font-bold text-center text-gray-900 dark:text-white mb-12">
|
||||
{t('marketing.pricing.faq.title')}
|
||||
</h2>
|
||||
<FAQAccordion items={[
|
||||
{
|
||||
question: t('marketing.pricing.faq.needPython.question'),
|
||||
answer: t('marketing.pricing.faq.needPython.answer')
|
||||
},
|
||||
{
|
||||
question: t('marketing.pricing.faq.exceedLimits.question'),
|
||||
answer: t('marketing.pricing.faq.exceedLimits.answer')
|
||||
},
|
||||
{
|
||||
question: t('marketing.pricing.faq.customDomain.question'),
|
||||
answer: t('marketing.pricing.faq.customDomain.answer')
|
||||
},
|
||||
{
|
||||
question: t('marketing.pricing.faq.dataSafety.question'),
|
||||
answer: t('marketing.pricing.faq.dataSafety.answer')
|
||||
}
|
||||
]} />
|
||||
<FAQAccordion
|
||||
items={[
|
||||
{
|
||||
question: t('marketing.pricing.faq.needPython.question'),
|
||||
answer: t('marketing.pricing.faq.needPython.answer'),
|
||||
},
|
||||
{
|
||||
question: t('marketing.pricing.faq.exceedLimits.question'),
|
||||
answer: t('marketing.pricing.faq.exceedLimits.answer'),
|
||||
},
|
||||
{
|
||||
question: t('marketing.pricing.faq.customDomain.question'),
|
||||
answer: t('marketing.pricing.faq.customDomain.answer'),
|
||||
},
|
||||
{
|
||||
question: t('marketing.pricing.faq.dataSafety.question'),
|
||||
answer: t('marketing.pricing.faq.dataSafety.answer'),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* CTA */}
|
||||
|
||||
Reference in New Issue
Block a user