import { IStorage } from "./storage"; import { User, InsertXpEvent } from "@shared/schema"; import { getLevelFromXP } from "@shared/gamification"; // Constants for XP Actions export const XP_RULES = { CREATE_TASK: 10, CREATE_SUBTASK: 5, UPDATE_TASK: 2, // Small amount for tweaking/updating COMPLETE_TASK: 50, COMPLETE_TASK_LATE: 20, // Reduced for overdue AI_ACTION: 5, // For using AI features LOGIN_STREAK: 100 }; export class GamificationService { private storage: IStorage; constructor(storage: IStorage) { this.storage = storage; } async awardXP(userId: string, source: string, amount?: number, description?: string): Promise<{ user: User, levelUp: boolean, oldLevel: number, newLevel: number }> { const user = await this.storage.getUser(userId); if (!user) throw new Error("User not found"); const xpAmount = amount || this.getXPForSource(source); const newTotalXP = (user.xp || 0) + xpAmount; // Check for level up const oldLevel = getLevelFromXP(user.xp || 0); const newLevel = getLevelFromXP(newTotalXP); const levelUp = newLevel > oldLevel; // Update User await this.storage.updateUserXP(userId, newTotalXP); // Log Event await this.storage.logXpEvent({ userId, amount: xpAmount, source, }); // If Level Up, we could log a special event or notification here? const updatedUser = await this.storage.getUser(userId); return { user: updatedUser!, levelUp, oldLevel, newLevel }; } private getXPForSource(source: string): number { switch (source) { case 'create_task': return XP_RULES.CREATE_TASK; case 'create_subtask': return XP_RULES.CREATE_SUBTASK; case 'update_task': return XP_RULES.UPDATE_TASK; case 'complete_task': return XP_RULES.COMPLETE_TASK; case 'complete_task_late': return XP_RULES.COMPLETE_TASK_LATE; case 'ai_action': return XP_RULES.AI_ACTION; case 'daily_streak': return XP_RULES.LOGIN_STREAK; default: return 0; } } }