UNPKG

backsplash-app

Version:
266 lines (223 loc) 7.51 kB
import { LicenseInfo, LicenseValidationResult, UsageStats, FREE_WALLPAPERS_PER_DAY, FREE_WALLPAPERS_PER_STYLE, FREE_STYLE_SELECTION_LIMIT, isStylePremium, LicenseTier, } from "@/types/license"; import { StoreService } from "./storeService"; import { getApiService } from "./apiServiceInstance"; import log from "@/logger"; export class LicenseService { private storeService: StoreService; private apiService: ReturnType<typeof getApiService>; constructor(storeService: StoreService) { this.storeService = storeService; this.apiService = getApiService(storeService); } /** * Get current license information */ getLicenseInfo(): LicenseInfo { const license = this.storeService.get("license") as LicenseInfo | undefined; if (!license) { return { licenseKey: null, isValid: false, isPremium: false, validatedAt: 0, plan: "free", }; } return license; } /** * Validate a license key via the apiService (which calls FastAPI) */ async validateLicenseKey(licenseKey: string): Promise<LicenseValidationResult> { try { log.info(`[LicenseService] Validating license key via apiService: ${licenseKey.substring(0, 8)}...`); // Set the license key first so apiService can validate it const isValid = await this.apiService.license.setLicenseKey(licenseKey); if (isValid) { // Get the license info from apiService const licenseInfo = this.apiService.license.getLicenseInfo(); // Convert to our internal format and store in new format for UI const result: LicenseValidationResult = { isValid: true, isPremium: licenseInfo.isActive, plan: licenseInfo.plan as LicenseTier, message: "License key is valid", purchaseDate: undefined, // Not available in current apiService format }; // Store in new format (for UI) const uiLicenseInfo: LicenseInfo = { licenseKey, isValid: true, isPremium: licenseInfo.isActive, validatedAt: Date.now(), plan: licenseInfo.plan as LicenseTier, purchaseDate: undefined, }; this.storeService.set("license", uiLicenseInfo); log.info("[LicenseService] License validated and stored successfully via apiService"); return result; } else { return { isValid: false, isPremium: false, message: "Invalid license key", plan: "free", }; } } catch (error) { log.error("[LicenseService] License validation failed:", error); return { isValid: false, isPremium: false, message: "Failed to validate license key. Please try again later.", plan: "free", }; } } /** * Clear stored license information */ clearLicense(): void { log.info("[LicenseService] Clearing license information"); // Clear both new and legacy formats this.storeService.delete("license"); this.storeService.delete("license-key"); this.storeService.delete("license-validation"); } /** * Get usage statistics for free users */ getUsageStats(): UsageStats { const stats = this.storeService.get("usageStats") as UsageStats | undefined; const today = new Date().toISOString().split("T")[0]; if (!stats || stats.lastResetDate !== today) { // Reset daily stats if it's a new day const newStats: UsageStats = { dailyGenerations: 0, lastResetDate: today, styleUsage: {}, }; this.storeService.set("usageStats", newStats); return newStats; } return stats; } /** * Record a wallpaper generation for usage tracking */ recordWallpaperGeneration(style: string): void { const license = this.getLicenseInfo(); // Don't track usage for premium users if (license.isPremium) { return; } const stats = this.getUsageStats(); const updatedStats: UsageStats = { ...stats, dailyGenerations: stats.dailyGenerations + 1, styleUsage: { ...stats.styleUsage, [style]: (stats.styleUsage[style] || 0) + 1, }, }; this.storeService.set("usageStats", updatedStats); log.debug(`[LicenseService] Recorded generation for ${style}. Daily: ${updatedStats.dailyGenerations}`); } /** * Check if user can generate a wallpaper for the given style */ canGenerateWallpaper(style: string): { canGenerate: boolean; reason?: string } { const license = this.getLicenseInfo(); const usageStats = this.getUsageStats(); // Premium users can generate unlimited wallpapers if (license.isPremium) { return { canGenerate: true }; } // Free users can only use free styles if (isStylePremium(style)) { return { canGenerate: false, reason: `${style} requires premium access. Upgrade to unlock all 120+ premium styles!`, }; } // Check daily limit for free users if (usageStats.dailyGenerations >= FREE_WALLPAPERS_PER_DAY) { return { canGenerate: false, reason: `Daily limit reached (${FREE_WALLPAPERS_PER_DAY} wallpapers). Upgrade for unlimited generation!`, }; } // Check per-style limit for free users const styleUsage = usageStats.styleUsage[style] || 0; if (styleUsage >= FREE_WALLPAPERS_PER_STYLE) { return { canGenerate: false, reason: `You've used all ${FREE_WALLPAPERS_PER_STYLE} free wallpapers for ${style}. Try another free style or upgrade!`, }; } return { canGenerate: true }; } /** * Check if user can select more styles (for free users with selection limit) */ canSelectMoreStyles(currentSelectionCount: number): { canSelect: boolean; reason?: string } { const license = this.getLicenseInfo(); // Premium users can select unlimited styles if (license.isPremium) { return { canSelect: true }; } // Check selection limit for free users if (currentSelectionCount >= FREE_STYLE_SELECTION_LIMIT) { return { canSelect: false, reason: `Free users can select up to ${FREE_STYLE_SELECTION_LIMIT} styles. Upgrade for unlimited selection!`, }; } return { canSelect: true }; } /** * Get remaining style selections for free users */ getRemainingStyleSelections(currentSelectionCount: number): number { const license = this.getLicenseInfo(); if (license.isPremium) { return -1; // Unlimited } return Math.max(0, FREE_STYLE_SELECTION_LIMIT - currentSelectionCount); } /** * Get remaining free generations for today */ getRemainingFreeGenerations(): number { const license = this.getLicenseInfo(); if (license.isPremium) { return -1; // Unlimited } const usageStats = this.getUsageStats(); return Math.max(0, FREE_WALLPAPERS_PER_DAY - usageStats.dailyGenerations); } /** * Get remaining generations for a specific style */ getRemainingStyleGenerations(style: string): number { const license = this.getLicenseInfo(); if (license.isPremium) { return -1; // Unlimited } if (isStylePremium(style)) { return 0; // Premium style not available to free users } const usageStats = this.getUsageStats(); const styleUsage = usageStats.styleUsage[style] || 0; return Math.max(0, FREE_WALLPAPERS_PER_STYLE - styleUsage); } }