Spaces:
Build error
Build error
| // Sistema de cr茅ditos por tier - PERMANENTES (se resetean solo si suben de nivel) | |
| // Los l铆mites no se resetean mensualmente, son parte de lo que pagan | |
| // Se resetean SOLO si el cliente actualiza su suscripci贸n a un tier superior | |
| export const TIER_LIMITS = { | |
| free: { | |
| influencers_per_month: 2, | |
| stories_per_month: 3, | |
| images_per_month: 5, | |
| videos_per_month: 1, | |
| content_per_month: 10, | |
| }, | |
| basic: { | |
| influencers_per_month: 10, | |
| stories_per_month: 15, | |
| images_per_month: 30, | |
| videos_per_month: 5, | |
| content_per_month: 50, | |
| }, | |
| premium: { | |
| influencers_per_month: 50, | |
| stories_per_month: 60, | |
| images_per_month: 150, | |
| videos_per_month: 20, | |
| content_per_month: 300, | |
| }, | |
| pro: { | |
| influencers_per_month: 500, | |
| stories_per_month: 999, | |
| images_per_month: 999, | |
| videos_per_month: 999, | |
| content_per_month: 999, | |
| }, | |
| }; | |
| export type Tier = keyof typeof TIER_LIMITS; | |
| export type ResourceType = keyof (typeof TIER_LIMITS)["free"]; | |
| // Ranking de tiers para comparaciones | |
| export const TIER_RANK: Record<Tier, number> = { | |
| free: 0, | |
| basic: 1, | |
| premium: 2, | |
| pro: 3, | |
| }; | |
| // Comprueba si el usuario con `userTier` puede suscribirse a una suscripci贸n de `subTier`. | |
| // Regla: el usuario solo puede crear suscripciones con un tier <= su propio tier. | |
| export function isSubscriptionTierAllowed(userTier: Tier | string, subTier: Tier | string) { | |
| const u = (userTier as Tier) in TIER_RANK ? (userTier as Tier) : (userTier as Tier); | |
| const s = (subTier as Tier) in TIER_RANK ? (subTier as Tier) : (subTier as Tier); | |
| const ur = TIER_RANK[u as Tier] ?? 0; | |
| const sr = TIER_RANK[s as Tier] ?? 0; | |
| return ur >= sr; | |
| } | |
| // Validar si usuario puede hacer la acci贸n | |
| // Los l铆mites son PERMANENTES para el tier contratado | |
| // Se resetean solo si el usuario sube a un tier superior o solicita un reset manual | |
| export async function validateUserCredit( | |
| db: any, | |
| userId: string, | |
| resourceType: ResourceType, | |
| tier: Tier | |
| ): Promise<{ allowed: boolean; reason?: string; remaining?: number }> { | |
| const limit = TIER_LIMITS[tier][resourceType]; | |
| // Contar TODOS los recursos creados (sin l铆mite de fecha) | |
| // Son permanentes para este tier de suscripci贸n | |
| let used = 0; | |
| try { | |
| if (resourceType === "influencers_per_month") { | |
| used = await db.aIInfluencer.count({ | |
| where: { | |
| // Sin filtro de fecha - son permanentes | |
| }, | |
| }); | |
| } else if (resourceType === "stories_per_month") { | |
| used = await db.story.count({ | |
| where: { | |
| // Sin filtro de fecha - son permanentes | |
| }, | |
| }); | |
| } else if (resourceType === "images_per_month") { | |
| used = await db.content.count({ | |
| where: { | |
| type: "image", | |
| // Sin filtro de fecha - son permanentes | |
| }, | |
| }); | |
| } else if (resourceType === "videos_per_month") { | |
| used = await db.content.count({ | |
| where: { | |
| type: "video", | |
| // Sin filtro de fecha - son permanentes | |
| }, | |
| }); | |
| } else if (resourceType === "content_per_month") { | |
| used = await db.content.count({ | |
| where: { | |
| // Sin filtro de fecha - son permanentes | |
| }, | |
| }); | |
| } | |
| } catch { | |
| // Si hay error, permitir (m谩s seguro que bloquear) | |
| used = 0; | |
| } | |
| const remaining = Math.max(0, limit - used); | |
| return { | |
| allowed: remaining > 0, | |
| reason: | |
| remaining === 0 | |
| ? `L铆mite de ${resourceType} alcanzado (${limit}). Necesitas subir a un tier superior.` | |
| : undefined, | |
| remaining, | |
| }; | |
| } | |
| // Log de uso (opcional, para futuro tracking) | |
| export async function logResourceUsage( | |
| db: any, | |
| userId: string, | |
| resourceType: ResourceType, | |
| resourceId: string | |
| ) { | |
| try { | |
| // Implementar cuando sea necesario | |
| // await db.resourceUsage.create({...}) | |
| } catch { | |
| // Ignorar errores de logging | |
| } | |
| } | |