mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
fix(folio): add parseTypedAmount helper matching app's parseCents
Raw user input like "50" must become 5000 cents, not 50. The existing parseDollarCents helper strips non-digits and so reads "50" as 50 cents, which is correct for formatted balance text but off by 100x for raw input from the amount field.
This commit is contained in:
1 parent
ee1fad1d30
commit
d88200f398
2 files changed
+72
No files matched your search
@@ -1,3 +1,19 @@
|
||||
// Parses raw user input in the transaction amount field into integer cents.
|
||||
// Mirrors the Folio app's parseCents: whole numbers like "50" become 5000
|
||||
// cents, decimals like "5.50" become 550, more than 2 decimals or non-numeric
|
||||
// input return 0. Leading +/- signs are tolerated and treated as positive.
|
||||
export function parseTypedAmount(text: string | undefined | null): number {
|
||||
if (!text) return 0;
|
||||
let trimmed = text.trim().replace(/,/g, "");
|
||||
if (trimmed.startsWith("+") || trimmed.startsWith("-")) trimmed = trimmed.slice(1);
|
||||
if (!/^\d+(\.\d{1,2})?$/.test(trimmed)) return 0;
|
||||
const dot = trimmed.indexOf(".");
|
||||
const whole = dot < 0 ? trimmed : trimmed.slice(0, dot);
|
||||
const frac = dot < 0 ? "" : trimmed.slice(dot + 1);
|
||||
const fracPadded = (frac + "00").slice(0, 2);
|
||||
return parseInt(whole, 10) * 100 + parseInt(fracPadded, 10);
|
||||
}
|
||||
|
||||
// When the last action is a tap (or double-tap) on the transaction Submit
|
||||
// button, the absolute change in total balance must equal the amount the
|
||||
// user typed. A double-submit lands two transactions and shifts the balance
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
|
||||
import { parseTypedAmount } from "../../../examples/folio/sanderling/predicates.ts";
|
||||
|
||||
test("empty string returns 0", () => {
|
||||
assert.equal(parseTypedAmount(""), 0);
|
||||
});
|
||||
|
||||
test("undefined returns 0", () => {
|
||||
assert.equal(parseTypedAmount(undefined), 0);
|
||||
});
|
||||
|
||||
test("null returns 0", () => {
|
||||
assert.equal(parseTypedAmount(null), 0);
|
||||
});
|
||||
|
||||
test("whole number 50 parses as 5000 cents", () => {
|
||||
assert.equal(parseTypedAmount("50"), 5000);
|
||||
});
|
||||
|
||||
test("decimal 5.50 parses as 550 cents", () => {
|
||||
assert.equal(parseTypedAmount("5.50"), 550);
|
||||
});
|
||||
|
||||
test("decimal 5.05 parses as 505 cents", () => {
|
||||
assert.equal(parseTypedAmount("5.05"), 505);
|
||||
});
|
||||
|
||||
test("one-decimal 0.5 parses as 50 cents", () => {
|
||||
assert.equal(parseTypedAmount("0.5"), 50);
|
||||
});
|
||||
|
||||
test("non-numeric returns 0", () => {
|
||||
assert.equal(parseTypedAmount("abc"), 0);
|
||||
});
|
||||
|
||||
test("too many decimals returns 0", () => {
|
||||
assert.equal(parseTypedAmount("5.123"), 0);
|
||||
});
|
||||
|
||||
test("zero returns 0", () => {
|
||||
assert.equal(parseTypedAmount("0"), 0);
|
||||
});
|
||||
|
||||
test("leading plus sign tolerated as positive", () => {
|
||||
assert.equal(parseTypedAmount("+50"), 5000);
|
||||
});
|
||||
|
||||
test("leading minus sign tolerated as positive", () => {
|
||||
assert.equal(parseTypedAmount("-50"), 5000);
|
||||
});
|
||||
|
||||
test("comma-separated thousands accepted", () => {
|
||||
assert.equal(parseTypedAmount("1,234.56"), 123456);
|
||||
});
|
||||
Reference in new issue
Block a user