Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions lib/__tests__/formatXLM.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { describe, it, expect } from "vitest";
import { formatXLM } from "../format";

describe("formatXLM amount formatter", () => {
it("formats 10000 XLM with thousand separators and 2 decimal places", () => {
expect(formatXLM(10000)).toBe("10,000.00 XLM");
});

it("formats 0 XLM as '0.00 XLM'", () => {
expect(formatXLM(0)).toBe("0.00 XLM");
});

it("formats fractional amounts (0.5 XLM) to 2 decimal places ('0.50 XLM')", () => {
expect(formatXLM(0.5)).toBe("0.50 XLM");
});

it("formats large numbers (1000000 XLM) with thousand separators ('1,000,000.00 XLM')", () => {
expect(formatXLM(1000000)).toBe("1,000,000.00 XLM");
});

it("formats negative values with a leading minus sign ('-500.00 XLM')", () => {
expect(formatXLM(-500)).toBe("-500.00 XLM");
});

it("handles string inputs cleanly", () => {
expect(formatXLM("10000")).toBe("10,000.00 XLM");
expect(formatXLM("0.5")).toBe("0.50 XLM");
expect(formatXLM("-500")).toBe("-500.00 XLM");
});

it("avoids floating-point representation rounding errors", () => {
expect(formatXLM(0.1 + 0.2)).toBe("0.30 XLM");
expect(formatXLM(1234.5678)).toBe("1,234.57 XLM");
});

it("handles invalid or NaN inputs gracefully with fallback", () => {
expect(formatXLM("invalid")).toBe("0.00 XLM");
});
});
18 changes: 18 additions & 0 deletions lib/format.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Formats a numeric or string XLM amount with thousand separators,
* 2 decimal places, and trailing " XLM" suffix.
* Handles negative values and prevents floating-point representation errors.
*/
export function formatXLM(amount: number | string | bigint): string {
const num = typeof amount === "string" ? Number(amount) : Number(amount);
if (isNaN(num)) {
return "0.00 XLM";
}

const formatted = num.toLocaleString("en-US", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});

return `${formatted} XLM`;
}
7 changes: 3 additions & 4 deletions lib/portfolio.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { formatXLM } from "./format";

export interface InvestmentPosition {
invoice_id: string;
invoice_title: string;
Expand All @@ -21,9 +23,6 @@ export function calculateActiveTotal(positions: InvestmentPosition[]): Portfolio

return {
activeTotal,
formattedTotal: `${activeTotal.toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})} XLM`,
formattedTotal: formatXLM(activeTotal),
};
}
Loading