Normalize derived issue timestamps to avoid 500s
This commit is contained in:
@@ -91,4 +91,23 @@ describe("deriveIssueUserContext", () => {
|
|||||||
expect(context.myLastTouchAt?.toISOString()).toBe("2026-03-06T11:30:00.000Z");
|
expect(context.myLastTouchAt?.toISOString()).toBe("2026-03-06T11:30:00.000Z");
|
||||||
expect(context.isUnreadForMe).toBe(false);
|
expect(context.isUnreadForMe).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("handles SQL timestamp strings without throwing", () => {
|
||||||
|
const context = deriveIssueUserContext(
|
||||||
|
makeIssue({
|
||||||
|
createdByUserId: "user-1",
|
||||||
|
createdAt: new Date("2026-03-06T09:00:00.000Z"),
|
||||||
|
}),
|
||||||
|
"user-1",
|
||||||
|
{
|
||||||
|
myLastCommentAt: "2026-03-06T10:00:00.000Z",
|
||||||
|
myLastReadAt: null,
|
||||||
|
lastExternalCommentAt: "2026-03-06T11:00:00.000Z",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(context.myLastTouchAt?.toISOString()).toBe("2026-03-06T10:00:00.000Z");
|
||||||
|
expect(context.lastExternalCommentAt?.toISOString()).toBe("2026-03-06T11:00:00.000Z");
|
||||||
|
expect(context.isUnreadForMe).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ type IssueUserCommentStats = {
|
|||||||
type IssueUserContextInput = {
|
type IssueUserContextInput = {
|
||||||
createdByUserId: string | null;
|
createdByUserId: string | null;
|
||||||
assigneeUserId: string | null;
|
assigneeUserId: string | null;
|
||||||
createdAt: Date;
|
createdAt: Date | string;
|
||||||
updatedAt: Date;
|
updatedAt: Date | string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function sameRunLock(checkoutRunId: string | null, actorRunId: string | null) {
|
function sameRunLock(checkoutRunId: string | null, actorRunId: string | null) {
|
||||||
@@ -179,18 +179,29 @@ export function deriveIssueUserContext(
|
|||||||
issue: IssueUserContextInput,
|
issue: IssueUserContextInput,
|
||||||
userId: string,
|
userId: string,
|
||||||
stats:
|
stats:
|
||||||
| { myLastCommentAt: Date | null; myLastReadAt: Date | null; lastExternalCommentAt: Date | null }
|
| {
|
||||||
|
myLastCommentAt: Date | string | null;
|
||||||
|
myLastReadAt: Date | string | null;
|
||||||
|
lastExternalCommentAt: Date | string | null;
|
||||||
|
}
|
||||||
| null
|
| null
|
||||||
| undefined,
|
| undefined,
|
||||||
) {
|
) {
|
||||||
const myLastCommentAt = stats?.myLastCommentAt ?? null;
|
const normalizeDate = (value: Date | string | null | undefined) => {
|
||||||
const myLastReadAt = stats?.myLastReadAt ?? null;
|
if (!value) return null;
|
||||||
const createdTouchAt = issue.createdByUserId === userId ? issue.createdAt : null;
|
if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;
|
||||||
const assignedTouchAt = issue.assigneeUserId === userId ? issue.updatedAt : null;
|
const parsed = new Date(value);
|
||||||
|
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
||||||
|
};
|
||||||
|
|
||||||
|
const myLastCommentAt = normalizeDate(stats?.myLastCommentAt);
|
||||||
|
const myLastReadAt = normalizeDate(stats?.myLastReadAt);
|
||||||
|
const createdTouchAt = issue.createdByUserId === userId ? normalizeDate(issue.createdAt) : null;
|
||||||
|
const assignedTouchAt = issue.assigneeUserId === userId ? normalizeDate(issue.updatedAt) : null;
|
||||||
const myLastTouchAt = [myLastCommentAt, myLastReadAt, createdTouchAt, assignedTouchAt]
|
const myLastTouchAt = [myLastCommentAt, myLastReadAt, createdTouchAt, assignedTouchAt]
|
||||||
.filter((value): value is Date => value instanceof Date)
|
.filter((value): value is Date => value instanceof Date)
|
||||||
.sort((a, b) => b.getTime() - a.getTime())[0] ?? null;
|
.sort((a, b) => b.getTime() - a.getTime())[0] ?? null;
|
||||||
const lastExternalCommentAt = stats?.lastExternalCommentAt ?? null;
|
const lastExternalCommentAt = normalizeDate(stats?.lastExternalCommentAt);
|
||||||
const isUnreadForMe = Boolean(
|
const isUnreadForMe = Boolean(
|
||||||
myLastTouchAt &&
|
myLastTouchAt &&
|
||||||
lastExternalCommentAt &&
|
lastExternalCommentAt &&
|
||||||
|
|||||||
Reference in New Issue
Block a user