From fc86ae8dbf277630278200a25e53306f117ff47b Mon Sep 17 00:00:00 2001 From: ghzhost Date: Sun, 16 Aug 2026 07:03:39 +0000 Subject: [PATCH] fix(dashboard): add merged stage to maintainer pipeline board (#88) --- jest.setup.ts | 4 ++ .../maintainer/MaintainerDashboard.test.ts | 51 +++++++++++++++++++ src/app/dashboard/maintainer/page.tsx | 5 +- 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 src/app/dashboard/maintainer/MaintainerDashboard.test.ts diff --git a/jest.setup.ts b/jest.setup.ts index e9e0a1c..cbc293d 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -1,3 +1,7 @@ // Extend Jest's built-in matchers with jest-dom's DOM-specific matchers // (e.g. toBeInTheDocument, toHaveAttribute, toHaveClass) import "@testing-library/jest-dom"; + +if (!process.env.NEXT_PUBLIC_STELLAR_NETWORK) { + process.env.NEXT_PUBLIC_STELLAR_NETWORK = "TESTNET"; +} diff --git a/src/app/dashboard/maintainer/MaintainerDashboard.test.ts b/src/app/dashboard/maintainer/MaintainerDashboard.test.ts new file mode 100644 index 0000000..0764c05 --- /dev/null +++ b/src/app/dashboard/maintainer/MaintainerDashboard.test.ts @@ -0,0 +1,51 @@ +import { pipelineStages } from "./page"; +import type { Bounty } from "@/types"; + +describe("MaintainerDashboard — pipeline stages and escrow alignment (#88)", () => { + it("includes the 'merged' status in pipelineStages with appropriate label", () => { + const mergedStage = pipelineStages.find((stage) => stage.status === "merged"); + expect(mergedStage).toBeDefined(); + expect(mergedStage?.label).toBe("Merged"); + }); + + it("contains all active stages aligned with totalEscrow calculation", () => { + const stageStatuses = pipelineStages.map((s) => s.status); + + // Check that open, funded, claimed, in_review, and merged are present + expect(stageStatuses).toContain("open"); + expect(stageStatuses).toContain("funded"); + expect(stageStatuses).toContain("claimed"); + expect(stageStatuses).toContain("in_review"); + expect(stageStatuses).toContain("merged"); + + // Finished or non-escrow statuses like paid, refunded, expired are intentionally omitted from pipeline board + expect(stageStatuses).not.toContain("paid"); + expect(stageStatuses).not.toContain("refunded"); + expect(stageStatuses).not.toContain("expired"); + }); + + it("ensures a merged bounty is captured and counted under the merged pipeline column", () => { + const mockBounties: Bounty[] = [ + { + id: "1", + org: "MergeFi", + repo: "frontend", + issueNumber: 88, + title: "Test merged bounty", + description: "Testing merged column", + reward: 50, + asset: "USDC", + status: "merged", + creator: "user1", + createdAt: "2026-08-16T00:00:00Z", + }, + ]; + + const mergedStage = pipelineStages.find((stage) => stage.status === "merged"); + expect(mergedStage).toBeDefined(); + + const filtered = mockBounties.filter((b) => b.status === mergedStage?.status); + expect(filtered).toHaveLength(1); + expect(filtered[0].title).toBe("Test merged bounty"); + }); +}); diff --git a/src/app/dashboard/maintainer/page.tsx b/src/app/dashboard/maintainer/page.tsx index 5a3f2a0..ca217c5 100644 --- a/src/app/dashboard/maintainer/page.tsx +++ b/src/app/dashboard/maintainer/page.tsx @@ -11,14 +11,15 @@ import { Avatar } from "@/components/ui/Avatar"; import { formatCurrency } from "@/lib/utils"; import type { Bounty, BountyStatus } from "@/types"; -const pipelineStages: { status: BountyStatus; label: string }[] = [ +export const pipelineStages: { status: BountyStatus; label: string }[] = [ { status: "open", label: "Open" }, { status: "funded", label: "Funded" }, { status: "claimed", label: "Claimed" }, { status: "in_review", label: "In review" }, + { status: "merged", label: "Merged" }, ]; -function PipelineColumn({ label, bounties }: { label: string; bounties: Bounty[] }) { +export function PipelineColumn({ label, bounties }: { label: string; bounties: Bounty[] }) { return (