fix: made payday overlay only go away when iuncome detected
All checks were successful
Deploy / deploy (push) Successful in 1m31s
Security Tests / security-non-db (push) Successful in 22s
Security Tests / security-db (push) Successful in 27s

This commit is contained in:
2026-03-28 21:37:36 -05:00
parent cb87c906c8
commit 339ab559d1

View File

@@ -4,6 +4,8 @@ import { z } from "zod";
import { fromZonedTime } from "date-fns-tz";
import { getUserMidnight } from "../allocator.js";
const DAY_MS = 24 * 60 * 60 * 1000;
type RateLimitRouteOptions = {
config: {
rateLimit: {
@@ -100,15 +102,42 @@ const paydayRoutes: FastifyPluginAsync<PaydayRoutesOptions> = async (app, opts)
userTimezone
);
const isPayday = isWithinPaydayWindow(now, nextPayday, 0, userTimezone);
const dayStart = getUserMidnight(userTimezone, now);
const dayEnd = new Date(dayStart.getTime() + 24 * 60 * 60 * 1000 - 1);
const scheduledIncomeToday = await app.prisma.incomeEvent.findFirst({
// Determine the currently due pay cycle:
// - on payday: cycle starts today
// - after payday: cycle starts on the last expected payday
const lookbackDaysByFrequency = {
weekly: 14,
biweekly: 28,
monthly: 62,
} as const;
const lookbackAnchor = new Date(
now.getTime() - lookbackDaysByFrequency[user.incomeFrequency] * DAY_MS
);
const currentCycleStart = calculateNextPayday(
user.firstIncomeDate,
user.incomeFrequency,
lookbackAnchor,
userTimezone
);
const isCycleDue = now.getTime() >= currentCycleStart.getTime();
const currentCycleEnd =
currentCycleStart.getTime() === nextPayday.getTime()
? calculateNextPayday(
user.firstIncomeDate,
user.incomeFrequency,
new Date(nextPayday.getTime() + DAY_MS),
userTimezone
)
: nextPayday;
const scheduledIncomeInCurrentCycle = await app.prisma.incomeEvent.findFirst({
where: {
userId,
isScheduledIncome: true,
postedAt: {
gte: dayStart,
lte: dayEnd,
gte: currentCycleStart,
lt: currentCycleEnd,
},
},
select: { id: true },
@@ -120,14 +149,17 @@ const paydayRoutes: FastifyPluginAsync<PaydayRoutesOptions> = async (app, opts)
firstIncomeDate: user.firstIncomeDate.toISOString(),
nextPayday: nextPayday.toISOString(),
isPayday,
currentCycleStart: currentCycleStart.toISOString(),
currentCycleEnd: currentCycleEnd.toISOString(),
isCycleDue,
pendingScheduledIncome: user.pendingScheduledIncome,
scheduledIncomeToday: !!scheduledIncomeToday,
shouldShowOverlay: isPayday && !scheduledIncomeToday,
scheduledIncomeInCurrentCycle: !!scheduledIncomeInCurrentCycle,
shouldShowOverlay: isCycleDue && !scheduledIncomeInCurrentCycle,
});
return {
shouldShowOverlay: isPayday && !scheduledIncomeToday,
pendingScheduledIncome: !scheduledIncomeToday,
shouldShowOverlay: isCycleDue && !scheduledIncomeInCurrentCycle,
pendingScheduledIncome: !scheduledIncomeInCurrentCycle,
nextPayday: nextPayday.toISOString(),
};
});