Phase 3 - credts, usage, plans app pages #Migrations

This commit is contained in:
IGNY8 VPS (Salman)
2026-01-06 21:28:13 +00:00
parent cb8e747387
commit 9ca048fb9d
37 changed files with 9328 additions and 1149 deletions

View File

@@ -0,0 +1,79 @@
/**
* Credit Check Utilities
* Pre-flight credit checks for AI operations
*/
import { getCreditBalance, type CreditBalance } from '../services/billing.api';
export interface CreditCheckResult {
hasEnoughCredits: boolean;
availableCredits: number;
requiredCredits: number;
shortfall: number;
}
/**
* Check if account has enough credits for an operation
* @param estimatedCredits - Estimated credits needed for the operation
* @returns Credit check result with balance info
*/
export async function checkCreditsBeforeOperation(
estimatedCredits: number
): Promise<CreditCheckResult> {
try {
const balance: CreditBalance = await getCreditBalance();
const hasEnoughCredits = balance.credits >= estimatedCredits;
return {
hasEnoughCredits,
availableCredits: balance.credits,
requiredCredits: estimatedCredits,
shortfall: Math.max(0, estimatedCredits - balance.credits),
};
} catch (error) {
console.error('Failed to check credit balance:', error);
// Return pessimistic result on error to prevent operation
return {
hasEnoughCredits: false,
availableCredits: 0,
requiredCredits: estimatedCredits,
shortfall: estimatedCredits,
};
}
}
/**
* Estimated credit costs for common operations
* These are estimates - actual costs depend on token usage
*/
export const ESTIMATED_CREDIT_COSTS = {
// Content Generation
content_generation_short: 5, // ~500 words
content_generation_medium: 10, // ~1000 words
content_generation_long: 20, // ~2000+ words
// Clustering & Planning
cluster_keywords: 3, // Per clustering operation
generate_content_ideas: 5, // Per batch of ideas
// Image Generation
image_basic: 2, // Basic quality
image_premium: 5, // Premium quality
// SEO Optimization
seo_analysis: 2,
seo_optimization: 3,
// Internal Linking
internal_linking: 2,
} as const;
/**
* Get estimated cost for an operation type
*/
export function getEstimatedCost(
operationType: keyof typeof ESTIMATED_CREDIT_COSTS,
quantity: number = 1
): number {
return ESTIMATED_CREDIT_COSTS[operationType] * quantity;
}

View File

@@ -16,12 +16,7 @@ export interface Plan {
max_sites?: number;
max_users?: number;
max_keywords?: number;
max_clusters?: number;
max_content_ideas?: number;
max_content_words?: number;
max_images_basic?: number;
max_images_premium?: number;
max_image_prompts?: number;
max_ahrefs_queries?: number;
included_credits?: number;
}
@@ -37,8 +32,8 @@ export const convertToPricingPlan = (plan: Plan): PricingPlan => {
const features: string[] = [];
// Dynamic counts - shown with numbers from backend
if (plan.max_content_ideas) {
features.push(`**${formatNumber(plan.max_content_ideas)} Pages/Articles per month**`);
if (plan.max_keywords) {
features.push(`**${formatNumber(plan.max_keywords)} Keywords**`);
}
if (plan.max_sites) {
features.push(`${plan.max_sites === 999999 ? 'Unlimited' : formatNumber(plan.max_sites)} Site${plan.max_sites > 1 && plan.max_sites !== 999999 ? 's' : ''}`);