Add improved production UI 4

This commit is contained in:
Urtzi Alfaro
2025-09-23 22:11:34 +02:00
parent 7892c5a739
commit 87310ced5f
17 changed files with 1658 additions and 296 deletions

View File

@@ -1,6 +1,3 @@
/**
* Subscription Service - Mirror backend subscription endpoints
*/
import { apiClient } from '../client';
import {
SubscriptionLimits,
@@ -9,9 +6,27 @@ import {
UsageSummary,
AvailablePlans,
PlanUpgradeValidation,
PlanUpgradeResult
PlanUpgradeResult,
SUBSCRIPTION_PLANS,
ANALYTICS_LEVELS,
AnalyticsLevel,
SubscriptionPlanKey,
PLAN_HIERARCHY,
ANALYTICS_HIERARCHY
} from '../types/subscription';
// Map plan keys to analytics levels based on backend data
const PLAN_TO_ANALYTICS_LEVEL: Record<SubscriptionPlanKey, AnalyticsLevel> = {
[SUBSCRIPTION_PLANS.STARTER]: ANALYTICS_LEVELS.BASIC,
[SUBSCRIPTION_PLANS.PROFESSIONAL]: ANALYTICS_LEVELS.ADVANCED,
[SUBSCRIPTION_PLANS.ENTERPRISE]: ANALYTICS_LEVELS.PREDICTIVE
};
// Cache for available plans
let cachedPlans: AvailablePlans | null = null;
let lastFetchTime: number | null = null;
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
export class SubscriptionService {
private readonly baseUrl = '/subscriptions';
@@ -106,13 +121,119 @@ export class SubscriptionService {
}).format(amount);
}
getPlanDisplayInfo(planKey: string): { name: string; color: string } {
const planInfo = {
starter: { name: 'Starter', color: 'blue' },
professional: { name: 'Professional', color: 'purple' },
enterprise: { name: 'Enterprise', color: 'amber' }
};
return planInfo[planKey as keyof typeof planInfo] || { name: 'Desconocido', color: 'gray' };
/**
* Fetch available subscription plans from the backend
*/
async fetchAvailablePlans(): Promise<AvailablePlans> {
const now = Date.now();
// Return cached data if it's still valid
if (cachedPlans && lastFetchTime && (now - lastFetchTime) < CACHE_DURATION) {
return cachedPlans;
}
try {
const plans = await apiClient.get<AvailablePlans>('/subscriptions/plans');
cachedPlans = plans;
lastFetchTime = now;
return plans;
} catch (error) {
console.error('Failed to fetch subscription plans:', error);
throw error;
}
}
/**
* Get plan display information
*/
async getPlanDisplayInfo(planKey: string) {
try {
const plans = await this.fetchAvailablePlans();
const plan = plans.plans[planKey];
if (plan) {
return {
name: plan.name,
color: this.getPlanColor(planKey),
description: plan.description,
monthlyPrice: plan.monthly_price
};
}
return { name: 'Desconocido', color: 'gray', description: '', monthlyPrice: 0 };
} catch (error) {
console.error('Failed to get plan display info:', error);
return { name: 'Desconocido', color: 'gray', description: '', monthlyPrice: 0 };
}
}
/**
* Get plan color based on plan key
*/
getPlanColor(planKey: string): string {
switch (planKey) {
case SUBSCRIPTION_PLANS.STARTER:
return 'blue';
case SUBSCRIPTION_PLANS.PROFESSIONAL:
return 'purple';
case SUBSCRIPTION_PLANS.ENTERPRISE:
return 'amber';
default:
return 'gray';
}
}
/**
* Check if a plan meets minimum requirements
*/
doesPlanMeetMinimum(plan: SubscriptionPlanKey, minimumRequired: SubscriptionPlanKey): boolean {
return PLAN_HIERARCHY[plan] >= PLAN_HIERARCHY[minimumRequired];
}
/**
* Get analytics level for a plan
*/
getAnalyticsLevelForPlan(plan: SubscriptionPlanKey): AnalyticsLevel {
return PLAN_TO_ANALYTICS_LEVEL[plan] || ANALYTICS_LEVELS.NONE;
}
/**
* Check if analytics level meets minimum requirements
*/
doesAnalyticsLevelMeetMinimum(level: AnalyticsLevel, minimumRequired: AnalyticsLevel): boolean {
return ANALYTICS_HIERARCHY[level] >= ANALYTICS_HIERARCHY[minimumRequired];
}
/**
* Get plan features
*/
async getPlanFeatures(planKey: string) {
try {
const plans = await this.fetchAvailablePlans();
const plan = plans.plans[planKey];
if (plan) {
return plan.features || {};
}
return {};
} catch (error) {
console.error('Failed to get plan features:', error);
return {};
}
}
/**
* Check if a plan has a specific feature
*/
async planHasFeature(planKey: string, featureName: string) {
try {
const features = await this.getPlanFeatures(planKey);
return featureName in features;
} catch (error) {
console.error('Failed to check plan feature:', error);
return false;
}
}
}