feat(driver-pwa): pure money/phone/amount helpers + tests

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
2026-06-18 19:13:16 +10:00
co-authored by claude-flow
parent 19b91d65c8
commit 34d3554f72
4 changed files with 73 additions and 0 deletions
@@ -0,0 +1,19 @@
import { describe, it, expect } from "vitest";
import { keypadReduce, withCommission } from "./amount";
describe("amount keypad", () => {
it("appends digits, ignores leading zero, caps length", () => {
expect(keypadReduce("0", "5")).toBe("5");
expect(keypadReduce("100", "0")).toBe("1000");
expect(keypadReduce("", "0")).toBe("");
expect(keypadReduce("999999", "9")).toBe("999999");
});
it("backspace removes last digit", () => {
expect(keypadReduce("105", "back")).toBe("10");
expect(keypadReduce("", "back")).toBe("");
});
it("withCommission computes total at given rate", () => {
expect(withCommission(1000, 0.052)).toEqual({ commission: 52, total: 1052 });
expect(withCommission(333, 0.052)).toEqual({ commission: 17.32, total: 350.32 });
});
});
+16
View File
@@ -0,0 +1,16 @@
const MAX_DIGITS = 6;
export function keypadReduce(current: string, key: string): string {
if (key === "back") return current.slice(0, -1);
if (!/^\d$/.test(key)) return current;
if (current === "0") return key === "0" ? "0" : key; // replace leading zero
if (current === "" && key === "0") return ""; // no leading zero from empty
if (current.length >= MAX_DIGITS) return current;
return current + key;
}
export function withCommission(base: number, rate: number): { commission: number; total: number } {
const commission = Math.round(base * rate * 100) / 100;
const total = Math.round((base + commission) * 100) / 100;
return { commission, total };
}
@@ -0,0 +1,17 @@
import { describe, it, expect } from "vitest";
import { formatMoney, formatPhone, digitsOnly } from "./format";
describe("format", () => {
it("formatMoney groups thousands and adds ₽", () => {
expect(formatMoney(1000)).toBe("1 000 ₽");
expect(formatMoney(-3200)).toBe("3 200 ₽");
expect(formatMoney(0)).toBe("0 ₽");
});
it("digitsOnly strips non-digits", () => {
expect(digitsOnly("+7 (914) 305-44-00")).toBe("79143054400");
});
it("formatPhone renders +7 mask progressively", () => {
expect(formatPhone("9143054400")).toBe("+7 914 305-44-00");
expect(formatPhone("914305")).toBe("+7 914 305");
});
});
+21
View File
@@ -0,0 +1,21 @@
export function digitsOnly(s: string): string {
return (s || "").replace(/\D/g, "");
}
export function formatMoney(rub: number): string {
const neg = rub < 0;
const abs = Math.abs(Math.round(rub));
const grouped = abs.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
return `${neg ? "" : ""}${grouped}`;
}
/** Render a Russian mobile from up-to-10 national digits as +7 914 305-44-00. */
export function formatPhone(national10: string): string {
const d = digitsOnly(national10).slice(0, 10);
const p: string[] = ["+7"];
if (d.length > 0) p.push(" " + d.slice(0, 3));
if (d.length > 3) p.push(" " + d.slice(3, 6));
if (d.length > 6) p.push("-" + d.slice(6, 8));
if (d.length > 8) p.push("-" + d.slice(8, 10));
return p.join("");
}