diff --git a/__tests__/invoiceFilters.test.ts b/__tests__/invoiceFilters.test.ts index 6174a1f..ae46235 100644 --- a/__tests__/invoiceFilters.test.ts +++ b/__tests__/invoiceFilters.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { applyInvoiceFilters, countActiveInvoiceFilters, EMPTY_INVOICE_FILTERS } from "../hooks/useInvoiceFilters"; -import type { Invoice } from "../utils/soroban"; +import { applyInvoiceFilters, countActiveInvoiceFilters, EMPTY_INVOICE_FILTERS } from "../src/hooks/useInvoiceFilters"; +import type { Invoice } from "../src/utils/soroban"; function makeInvoice( id: bigint, @@ -9,11 +9,12 @@ function makeInvoice( dueDate: bigint, discountRate: number, token?: string, + payer = "GBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBRY", ): Invoice { return { id, freelancer: "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF", - payer: "GBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBRY", + payer, amount, due_date: dueDate, discount_rate: discountRate, @@ -26,9 +27,9 @@ function makeInvoice( describe("invoice filter logic", () => { const invoices: Invoice[] = [ - makeInvoice(101n, "Pending", 100n * 10_000_000n, 1_760_000_000n, 300, "token-usdc"), - makeInvoice(202n, "Funded", 500n * 10_000_000n, 1_770_000_000n, 900, "token-eurc"), - makeInvoice(303n, "Paid", 900n * 10_000_000n, 1_780_000_000n, 1200, "token-xlm"), + makeInvoice(101n, "Pending", 100n * 10_000_000n, 1_760_000_000n, 300, "token-usdc", "PAYER_LOW"), + makeInvoice(202n, "Funded", 500n * 10_000_000n, 1_770_000_000n, 900, "token-eurc", "PAYER_HIGH"), + makeInvoice(303n, "Paid", 900n * 10_000_000n, 1_780_000_000n, 1200, "token-xlm", "PAYER_UNKNOWN"), ]; it("searches by id and address fragments", () => { @@ -68,6 +69,25 @@ describe("invoice filter logic", () => { expect(filtered.map((invoice) => invoice.id)).toEqual([202n]); }); + it("filters by minimum payer reputation score", () => { + const filtered = applyInvoiceFilters( + invoices, + { + ...EMPTY_INVOICE_FILTERS, + minPayerReputation: "75", + }, + { + resolvePayerReputation: (invoice) => { + if (invoice.payer === "PAYER_LOW") return 40; + if (invoice.payer === "PAYER_HIGH") return 90; + return null; + }, + }, + ); + + expect(filtered.map((invoice) => invoice.id)).toEqual([202n]); + }); + it("counts active filter groups correctly", () => { expect( countActiveInvoiceFilters({ @@ -76,7 +96,8 @@ describe("invoice filter logic", () => { statuses: ["Pending"], minAmount: "10", token: "USDC", + minPayerReputation: "80", }), - ).toBe(4); + ).toBe(5); }); }); diff --git a/src/components/InvoiceFilterBar.tsx b/src/components/InvoiceFilterBar.tsx index 989761a..4f957d9 100644 --- a/src/components/InvoiceFilterBar.tsx +++ b/src/components/InvoiceFilterBar.tsx @@ -13,6 +13,7 @@ type InvoiceFilterBarProps = { onClearFilters: () => void; activeFilterCount: number; className?: string; + showReputationFilter?: boolean; }; const TOKEN_OPTIONS = ["USDC", "EURC", "XLM"] as const; @@ -23,6 +24,7 @@ export default function InvoiceFilterBar({ onClearFilters, activeFilterCount, className, + showReputationFilter = false, }: InvoiceFilterBarProps) { const [isAdvancedOpen, setIsAdvancedOpen] = useState(false); diff --git a/src/components/LPDashboard.tsx b/src/components/LPDashboard.tsx index da5df7b..9ad39a4 100644 --- a/src/components/LPDashboard.tsx +++ b/src/components/LPDashboard.tsx @@ -542,6 +542,7 @@ export default function LPDashboard() { onFiltersChange={setFilters} onClearFilters={clearFilters} activeFilterCount={activeFilterCount} + showReputationFilter />