diff --git a/src/commands/economy/daily.ts b/src/commands/economy/daily.ts index be84843..aafb290 100644 --- a/src/commands/economy/daily.ts +++ b/src/commands/economy/daily.ts @@ -15,9 +15,10 @@ export const daily = createCommand({ const embed = new EmbedBuilder() .setTitle("šŸ’° Daily Reward Claimed!") - .setDescription(`You claimed ** ${result.amount}** Astral Units!`) + .setDescription(`You claimed ** ${result.amount}** Astral Units!${result.isWeekly ? `\nšŸŽ‰ **Weekly Bonus!** +${result.weeklyBonus} extra!` : ''}`) .addFields( { name: "Streak", value: `šŸ”„ ${result.streak} days`, inline: true }, + { name: "Weekly Progress", value: `${"🟩".repeat(result.streak % 7 || 7)}${"⬜".repeat(7 - (result.streak % 7 || 7))} (${result.streak % 7 || 7}/7)`, inline: true }, { name: "Next Reward", value: `< t:${Math.floor(result.nextReadyAt.getTime() / 1000)}: R > `, inline: true } ) .setColor("Gold") diff --git a/src/lib/config.ts b/src/lib/config.ts index adf3b3a..a56e08a 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -18,6 +18,7 @@ export interface GameConfigType { daily: { amount: bigint; streakBonus: bigint; + weeklyBonus: bigint; cooldownMs: number; }, transfers: { @@ -79,6 +80,7 @@ const configSchema = z.object({ daily: z.object({ amount: bigIntSchema, streakBonus: bigIntSchema, + weeklyBonus: bigIntSchema.default(50n), cooldownMs: z.number(), }), transfers: z.object({ diff --git a/src/modules/economy/economy.service.test.ts b/src/modules/economy/economy.service.test.ts index fc9e158..5c1bcc5 100644 --- a/src/modules/economy/economy.service.test.ts +++ b/src/modules/economy/economy.service.test.ts @@ -62,6 +62,7 @@ mock.module("@/lib/config", () => ({ daily: { amount: 100n, streakBonus: 10n, + weeklyBonus: 50n, cooldownMs: 86400000, // 24 hours } } @@ -139,6 +140,7 @@ describe("economyService", () => { expect(result.streak).toBe(6); // Base 100 + (6-1)*10 = 150 expect(result.amount).toBe(150n); + expect(result.isWeekly).toBe(false); // Check updates expect(mockUpdate).toHaveBeenCalledWith(users); @@ -146,6 +148,28 @@ describe("economyService", () => { expect(mockInsert).toHaveBeenCalledWith(transactions); }); + it("should claim weekly bonus correctly on 7th day", async () => { + const recentPast = new Date("2023-01-01T11:00:00Z"); + + mockFindFirst + .mockResolvedValueOnce({ expiresAt: recentPast }) + .mockResolvedValueOnce({ id: 1n, dailyStreak: 6, balance: 1000n }); // User currently at 6 days + + const result = await economyService.claimDaily("1"); + + expect(result.claimed).toBe(true); + // Streak should increase: 6 + 1 = 7 + expect(result.streak).toBe(7); + + // Base: 100 + // Streak Bonus: (7-1)*10 = 60 + // Weekly Bonus: 50 + // Total: 210 + expect(result.amount).toBe(210n); + expect(result.isWeekly).toBe(true); + expect(result.weeklyBonus).toBe(50n); + }); + it("should throw if cooldown is active", async () => { const future = new Date("2023-01-02T12:00:00Z"); // +24h mockFindFirst.mockResolvedValue({ expiresAt: future }); diff --git a/src/modules/economy/economy.service.ts b/src/modules/economy/economy.service.ts index dc14587..8749b8e 100644 --- a/src/modules/economy/economy.service.ts +++ b/src/modules/economy/economy.service.ts @@ -106,7 +106,11 @@ export const economyService = { const bonus = (BigInt(streak) - 1n) * config.economy.daily.streakBonus; - const totalReward = config.economy.daily.amount + bonus; + // Weekly bonus check + const isWeeklyCurrent = streak > 0 && streak % 7 === 0; + const weeklyBonusAmount = isWeeklyCurrent ? config.economy.daily.weeklyBonus : 0n; + + const totalReward = config.economy.daily.amount + bonus + weeklyBonusAmount; await txFn.update(users) .set({ balance: sql`${users.balance} + ${totalReward}`, @@ -138,7 +142,7 @@ export const economyService = { description: `Daily reward (Streak: ${streak})`, }); - return { claimed: true, amount: totalReward, streak, nextReadyAt }; + return { claimed: true, amount: totalReward, streak, nextReadyAt, isWeekly: isWeeklyCurrent, weeklyBonus: weeklyBonusAmount }; }, tx); },