From be0e69320332b30760b94365bcb2d255eabfd175 Mon Sep 17 00:00:00 2001 From: iajibose Date: Fri, 26 Jun 2026 11:48:47 +0100 Subject: [PATCH] Fix: Add currentAmount aggregation to posts list API for help-request progress Adds helpContributions _sum aggregation via groupBy to the GET /api/posts endpoint so each post includes the total amount raised, and updates the mapper and tests accordingly. Closes #355 --- app/app/api/posts/route.ts | 24 +++++++++++++++++++++++- app/lib/map-api-post.ts | 1 + app/tests/api/posts.test.ts | 28 ++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/app/app/api/posts/route.ts b/app/app/api/posts/route.ts index 5a69f04..6a6aead 100644 --- a/app/app/api/posts/route.ts +++ b/app/app/api/posts/route.ts @@ -288,7 +288,29 @@ const GET = async (request: NextRequest) => { prisma.post.count({ where }), ]); - return apiSuccess({ posts, page, limit, total }); + const postIds = posts.map((p: { id: string }) => p.id); + const contributionAggregates = + postIds.length > 0 + ? await prisma.helpContribution.groupBy({ + by: ["postId"], + where: { postId: { in: postIds } }, + _sum: { amount: true }, + }) + : []; + + const contributionMap = new Map( + contributionAggregates.map((agg: { postId: string; _sum: { amount: number | null } }) => [ + agg.postId, + agg._sum.amount ?? 0, + ]), + ); + + const postsWithCurrentAmount = posts.map((post: { id: string }) => ({ + ...post, + currentAmount: contributionMap.get(post.id) ?? 0, + })); + + return apiSuccess({ posts: postsWithCurrentAmount, page, limit, total }); } catch (error) { return apiError("Failed to fetch posts", 500); } diff --git a/app/lib/map-api-post.ts b/app/lib/map-api-post.ts index 0d7ce7d..c6cfd42 100644 --- a/app/lib/map-api-post.ts +++ b/app/lib/map-api-post.ts @@ -40,6 +40,7 @@ export function mapApiPostToClientPost(apiPost: Record | null | (apiPost.entriesCount as number) ?? (typeof _count?.entries === "number" ? _count.entries : 0) ?? (Array.isArray(apiPost.entries) ? apiPost.entries.length : 0), + currentAmount: (apiPost.currentAmount as number | undefined) ?? 0, author: { id: (user?.id as string) ?? (apiPost.userId as string) ?? "", name: (user?.name as string) ?? "Unknown User", diff --git a/app/tests/api/posts.test.ts b/app/tests/api/posts.test.ts index 2a5dd5a..37ec62d 100644 --- a/app/tests/api/posts.test.ts +++ b/app/tests/api/posts.test.ts @@ -180,6 +180,34 @@ describe("Posts API", () => { ); }); + it("should return currentAmount as sum of helpContributions for each post", async () => { + prisma.post.findMany = vi.fn().mockResolvedValue([ + { id: "post_help_1", title: "Help Request Post", type: "request", user: testUser }, + { id: "post_help_2", title: "Another Help Post", type: "request", user: testUser }, + { id: "post_no_contrib", title: "No Contributions Post", type: "request", user: testUser }, + ]); + prisma.post.count = vi.fn().mockResolvedValue(3); + (prisma.helpContribution as any).groupBy = vi.fn().mockResolvedValue([ + { postId: "post_help_1", _sum: { amount: 1250 } }, + { postId: "post_help_2", _sum: { amount: 300 } }, + ]); + + const request = createMockRequest("http://localhost:3000/api/posts?type=request"); + const response = await GET(request); + const { status, data } = await parseResponse(response); + + expect(status).toBe(200); + expect(data.data.posts).toHaveLength(3); + + const post1 = data.data.posts.find((p: any) => p.id === "post_help_1"); + const post2 = data.data.posts.find((p: any) => p.id === "post_help_2"); + const post3 = data.data.posts.find((p: any) => p.id === "post_no_contrib"); + + expect(post1.currentAmount).toBe(1250); + expect(post2.currentAmount).toBe(300); + expect(post3.currentAmount).toBe(0); + }); + it("applies deadline active filter when filter=active", async () => { prisma.post.findMany = vi.fn().mockResolvedValue([]); prisma.post.count = vi.fn().mockResolvedValue(0);