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:
poduck
2025-12-12 21:00:54 -05:00
parent d25c578e59
commit b384d9912a
183 changed files with 47627 additions and 3955 deletions

View File

@@ -114,6 +114,7 @@ const ContractSigning = React.lazy(() => import('./pages/ContractSigning')); //
const PageEditor = React.lazy(() => import('./pages/PageEditor')); // Import PageEditor
const PublicPage = React.lazy(() => import('./pages/PublicPage')); // Import PublicPage
const BookingFlow = React.lazy(() => import('./pages/BookingFlow')); // Import Booking Flow
const Locations = React.lazy(() => import('./pages/Locations')); // Import Locations management page
// Settings pages
const SettingsLayout = React.lazy(() => import('./layouts/SettingsLayout'));
@@ -832,6 +833,16 @@ const AppContent: React.FC = () => {
)
}
/>
<Route
path="/locations"
element={
hasAccess(['owner', 'manager']) ? (
<Locations />
) : (
<Navigate to="/" />
)
}
/>
<Route
path="/my-availability"
element={