105 lines
2.6 KiB
TypeScript
105 lines
2.6 KiB
TypeScript
import { usePrisma } from "../utils/prisma";
|
|
|
|
export async function getActiveStreak(userId: string) {
|
|
const db = usePrisma();
|
|
return db.streak.findFirst({
|
|
where: { userId, isActive: true },
|
|
});
|
|
}
|
|
|
|
export async function upsertStreak(
|
|
userId: string,
|
|
data: { avgMonthlySavings?: number | null; startDate?: string | null },
|
|
) {
|
|
const db = usePrisma();
|
|
const today = new Date();
|
|
today.setUTCHours(0, 0, 0, 0);
|
|
|
|
// Allow setting a past start date (e.g. from onboarding "last played" selection)
|
|
const startDate = data.startDate ? new Date(data.startDate) : today;
|
|
startDate.setUTCHours(0, 0, 0, 0);
|
|
|
|
const existing = await db.streak.findFirst({ where: { userId } });
|
|
|
|
if (existing) {
|
|
const streak = await db.streak.update({
|
|
where: { id: existing.id },
|
|
data: {
|
|
startDate,
|
|
currentDays: 0,
|
|
isActive: true,
|
|
...(data.avgMonthlySavings !== undefined
|
|
? { avgMonthlySavings: data.avgMonthlySavings }
|
|
: {}),
|
|
},
|
|
});
|
|
await addStreakEvent(userId, "started");
|
|
return streak;
|
|
}
|
|
|
|
const streak = await db.streak.create({
|
|
data: {
|
|
userId,
|
|
startDate,
|
|
currentDays: 0,
|
|
longestDays: 0,
|
|
avgMonthlySavings: data.avgMonthlySavings ?? null,
|
|
isActive: true,
|
|
},
|
|
});
|
|
await addStreakEvent(userId, "started");
|
|
return streak;
|
|
}
|
|
|
|
export async function resetStreak(
|
|
streakId: string,
|
|
longestDays: number,
|
|
userId: string,
|
|
reason: "blocker_off" | "relapse" | "manual" = "manual",
|
|
) {
|
|
const db = usePrisma();
|
|
const today = new Date();
|
|
today.setUTCHours(0, 0, 0, 0);
|
|
const streak = await db.streak.update({
|
|
where: { id: streakId },
|
|
data: { currentDays: 0, startDate: today, longestDays },
|
|
});
|
|
await addStreakEvent(userId, "reset", { reason, previousDays: longestDays });
|
|
return streak;
|
|
}
|
|
|
|
export async function updateStreakSavings(streakId: string, amount: number) {
|
|
const db = usePrisma();
|
|
return db.streak.update({
|
|
where: { id: streakId },
|
|
data: { avgMonthlySavings: amount },
|
|
});
|
|
}
|
|
|
|
export async function deleteUserStreaks(userId: string) {
|
|
const db = usePrisma();
|
|
return db.streak.deleteMany({ where: { userId } });
|
|
}
|
|
|
|
// --- Streak Events ---
|
|
|
|
export async function addStreakEvent(
|
|
userId: string,
|
|
type: "started" | "reset" | "milestone" | "relapse",
|
|
meta?: Record<string, unknown>,
|
|
) {
|
|
const db = usePrisma();
|
|
return db.streakEvent.create({
|
|
data: { userId, type, meta: meta ?? undefined },
|
|
});
|
|
}
|
|
|
|
export async function getStreakEvents(userId: string, limit = 50) {
|
|
const db = usePrisma();
|
|
return db.streakEvent.findMany({
|
|
where: { userId },
|
|
orderBy: { createdAt: "desc" },
|
|
take: limit,
|
|
});
|
|
}
|