Skip to content

Commit 686263b

Browse files
committed
test frontend fix
1 parent 59e42a2 commit 686263b

4 files changed

Lines changed: 35 additions & 29 deletions

File tree

‎backend/lambda.zip‎

-2.48 MB
Binary file not shown.

‎backend/package-lock.json‎

Lines changed: 2 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎backend/src/lambda.ts‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
import { Handler } from 'aws-lambda';
22
import serverlessExpress from '@vendia/serverless-express';
33
import { NestFactory } from '@nestjs/core';
4+
import { ValidationPipe } from '@nestjs/common';
5+
import cookieParser from 'cookie-parser';
46
import { AppModule } from './app.module';
57

68
let cachedHandler: any;
79

810
async function bootstrapServer() {
911
const app = await NestFactory.create(AppModule);
10-
12+
1113
app.enableCors({
1214
origin: 'https://main.d3nms49d928y9k.amplifyapp.com',
1315
credentials: true,
1416
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
1517
allowedHeaders: ['Content-Type', 'Authorization'],
1618
});
17-
19+
app.use(cookieParser()); // fixes req.cookies undefined
20+
app.useGlobalPipes(new ValidationPipe()); // was also missing vs main.ts
21+
1822
await app.init();
1923
const expressApp = app.getHttpAdapter().getInstance();
2024
return serverlessExpress({ app: expressApp });

‎frontend/src/main-page/cash-flow/projection.ts‎

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,25 +127,46 @@ export function buildCashflowProjection(
127127
}
128128
} else {
129129
// Recurring: expand occurrences within the projection window
130-
const interval = getIntervalMonths(cost);
131-
if (interval <= 0) continue; // safety guard
130+
const interval = Number(getIntervalMonths(cost));
131+
if (!Number.isFinite(interval) || interval <= 0) continue; // bad data guard
132+
133+
// Sub-monthly (e.g. weekly = 0.25): setMonth can't step by fractions,
134+
// so charge every month from the start, scaled by occurrences per month
135+
if (interval < 1) {
136+
const startKey = toMonthKey(cost.date);
137+
const perMonth = 1 / interval;
138+
for (const key of monthKeys) {
139+
if (key < startKey) continue;
140+
const adjusted = getAdjustedCostAmount(cost, key, settings) * perMonth;
141+
costBuckets.set(key, costBuckets.get(key)! + adjusted);
142+
}
143+
continue;
144+
}
145+
146+
const step = Math.round(interval); // setMonth only takes whole months
147+
const MAX_STEPS = 1000; // hard stop so bad data can't freeze the tab
148+
let steps = 0;
132149

133150
// Parse as local date to avoid UTC shift
134151
const [cy, cm] = cost.date.split("-").map(Number);
135152
const cursor = new Date(cy, cm - 1, 1);
136153

137154
// Advance past occurrences that fall before the exact start date
138-
while (new Date(cost.date) < new Date(settings.startDate) && toMonthKey(cursor) < toMonthKey(new Date(cy, cm, 1))) {
139-
cursor.setMonth(cursor.getMonth() + interval);
155+
while (
156+
new Date(cost.date) < new Date(settings.startDate) &&
157+
toMonthKey(cursor) < toMonthKey(new Date(cy, cm, 1)) &&
158+
steps++ < MAX_STEPS
159+
) {
160+
cursor.setMonth(cursor.getMonth() + step);
140161
}
141162

142-
while (toMonthKey(cursor) <= endKey) {
163+
while (toMonthKey(cursor) <= endKey && steps++ < MAX_STEPS) {
143164
const key = toMonthKey(cursor);
144165
if (costBuckets.has(key)) {
145166
const adjusted = getAdjustedCostAmount(cost, key, settings);
146167
costBuckets.set(key, costBuckets.get(key)! + adjusted);
147168
}
148-
cursor.setMonth(cursor.getMonth() + interval);
169+
cursor.setMonth(cursor.getMonth() + step);
149170
}
150171
}
151172
}

0 commit comments

Comments
 (0)