diff --git a/shared/db/schema/users.ts b/shared/db/schema/users.ts index 0b68988..59eb368 100644 --- a/shared/db/schema/users.ts +++ b/shared/db/schema/users.ts @@ -50,7 +50,7 @@ export const userTimers = pgTable('user_timers', { userId: bigint('user_id', { mode: 'bigint' }) .references(() => users.id, { onDelete: 'cascade' }).notNull(), type: varchar('type', { length: 50 }).notNull(), // 'COOLDOWN', 'EFFECT', 'ACCESS' - key: varchar('key', { length: 100 }).notNull(), // 'daily', 'chn_12345', 'xp_boost' + key: varchar('key', { length: 100 }).notNull(), // TimerKey, 'chn_12345', 'xp_boost' expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(), metadata: jsonb('metadata').default({}), }, (table) => [ diff --git a/shared/lib/constants.test.ts b/shared/lib/constants.test.ts new file mode 100644 index 0000000..5cf6af9 --- /dev/null +++ b/shared/lib/constants.test.ts @@ -0,0 +1,44 @@ +import { describe, it, expect } from "bun:test"; +import { TimerKey, TimerType, TransactionType } from "./constants"; + +describe("TimerKey", () => { + it("should have CHAT_XP value", () => { + expect(TimerKey.CHAT_XP).toBe("chat_xp" as TimerKey); + }); + + it("should have DAILY value", () => { + expect(TimerKey.DAILY).toBe("daily" as TimerKey); + }); + + it("should have WEEKLY value", () => { + expect(TimerKey.WEEKLY).toBe("weekly" as TimerKey); + }); +}); + +describe("TimerType", () => { + it("should have COOLDOWN value", () => { + expect(TimerType.COOLDOWN).toBe("COOLDOWN" as TimerType); + }); + + it("should have EFFECT value", () => { + expect(TimerType.EFFECT).toBe("EFFECT" as TimerType); + }); + + it("should have ACCESS value", () => { + expect(TimerType.ACCESS).toBe("ACCESS" as TimerType); + }); +}); + +describe("TransactionType", () => { + it("should have DAILY_REWARD value", () => { + expect(TransactionType.DAILY_REWARD).toBe("DAILY_REWARD" as TransactionType); + }); + + it("should have TRANSFER_IN value", () => { + expect(TransactionType.TRANSFER_IN).toBe("TRANSFER_IN" as TransactionType); + }); + + it("should have TRANSFER_OUT value", () => { + expect(TransactionType.TRANSFER_OUT).toBe("TRANSFER_OUT" as TransactionType); + }); +}); diff --git a/shared/lib/constants.ts b/shared/lib/constants.ts index 653d187..0962f51 100644 --- a/shared/lib/constants.ts +++ b/shared/lib/constants.ts @@ -10,6 +10,12 @@ export enum TimerType { TRIVIA_COOLDOWN = 'TRIVIA_COOLDOWN', } +export enum TimerKey { + CHAT_XP = 'chat_xp', + DAILY = 'daily', + WEEKLY = 'weekly', +} + export enum EffectType { ADD_XP = 'ADD_XP', ADD_BALANCE = 'ADD_BALANCE', diff --git a/shared/modules/economy/economy.service.ts b/shared/modules/economy/economy.service.ts index f12eab0..c7a7a57 100644 --- a/shared/modules/economy/economy.service.ts +++ b/shared/modules/economy/economy.service.ts @@ -4,7 +4,7 @@ import { config } from "@shared/lib/config"; import { withTransaction } from "@/lib/db"; import type { Transaction } from "@shared/lib/types"; import { UserError } from "@shared/lib/errors"; -import { TimerType, TransactionType } from "@shared/lib/constants"; +import { TimerKey, TimerType, TransactionType } from "@shared/lib/constants"; export const economyService = { transfer: async (fromUserId: string, toUserId: string, amount: bigint, tx?: Transaction) => { @@ -82,7 +82,7 @@ export const economyService = { where: and( eq(userTimers.userId, BigInt(userId)), eq(userTimers.type, TimerType.COOLDOWN), - eq(userTimers.key, 'daily') + eq(userTimers.key, TimerKey.DAILY) ), }); @@ -141,7 +141,7 @@ export const economyService = { .values({ userId: BigInt(userId), type: TimerType.COOLDOWN, - key: 'daily', + key: TimerKey.DAILY, expiresAt: nextReadyAt, }) .onConflictDoUpdate({ diff --git a/shared/modules/leveling/leveling.service.ts b/shared/modules/leveling/leveling.service.ts index a009c51..7b6f7ed 100644 --- a/shared/modules/leveling/leveling.service.ts +++ b/shared/modules/leveling/leveling.service.ts @@ -3,7 +3,7 @@ import { eq, sql, and } from "drizzle-orm"; import { withTransaction } from "@/lib/db"; import { config } from "@shared/lib/config"; import type { Transaction } from "@shared/lib/types"; -import { TimerType } from "@shared/lib/constants"; +import { TimerKey, TimerType } from "@shared/lib/constants"; export const levelingService = { // Calculate total XP required to REACH a specific level (Cumulative) @@ -84,7 +84,7 @@ export const levelingService = { where: and( eq(userTimers.userId, BigInt(id)), eq(userTimers.type, TimerType.COOLDOWN), - eq(userTimers.key, 'chat_xp') + eq(userTimers.key, TimerKey.CHAT_XP) ), }); @@ -120,7 +120,7 @@ export const levelingService = { .values({ userId: BigInt(id), type: TimerType.COOLDOWN, - key: 'chat_xp', + key: TimerKey.CHAT_XP, expiresAt: nextReadyAt, }) .onConflictDoUpdate({