Skip to content

Commit ac7c669

Browse files
committed
refactor(domain): extract padDecimalOnBlur helper with unit tests
1 parent b17ffe1 commit ac7c669

6 files changed

Lines changed: 73 additions & 29 deletions

File tree

packages/app/src/modules/declaration-remuneration/shared/PayGapTable.tsx

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
formatGap,
66
gapLevel,
77
normalizeDecimalInput,
8-
padDecimalToTwo,
8+
padDecimalOnBlur,
99
} from "~/modules/domain";
1010
import type { PayGapField, PayGapRow } from "../types";
1111
import common from "./common.module.scss";
@@ -89,12 +89,11 @@ export function PayGapTable({
8989
className={`fr-input ${common.numericInput}`}
9090
disabled={disabled}
9191
inputMode="decimal"
92-
onBlur={() => {
93-
const padded = padDecimalToTwo(row.womenValue);
94-
if (padded !== row.womenValue) {
95-
onRowChange(i, "womenValue", padded);
96-
}
97-
}}
92+
onBlur={() =>
93+
padDecimalOnBlur(row.womenValue, (v) =>
94+
onRowChange(i, "womenValue", v),
95+
)
96+
}
9897
onChange={(e) =>
9998
onRowChange(i, "womenValue", e.target.value)
10099
}
@@ -111,12 +110,11 @@ export function PayGapTable({
111110
className={`fr-input ${common.numericInput}`}
112111
disabled={disabled}
113112
inputMode="decimal"
114-
onBlur={() => {
115-
const padded = padDecimalToTwo(row.menValue);
116-
if (padded !== row.menValue) {
117-
onRowChange(i, "menValue", padded);
118-
}
119-
}}
113+
onBlur={() =>
114+
padDecimalOnBlur(row.menValue, (v) =>
115+
onRowChange(i, "menValue", v),
116+
)
117+
}
120118
onChange={(e) =>
121119
onRowChange(i, "menValue", e.target.value)
122120
}

packages/app/src/modules/declaration-remuneration/steps/step4/QuartileTable.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { QuartileData } from "~/modules/declaration-remuneration/types";
66
import {
77
computePercentage,
88
displayDecimal,
9-
padDecimalToTwo,
9+
padDecimalOnBlur,
1010
} from "~/modules/domain";
1111
import stepStyles from "../Step4QuartileDistribution.module.scss";
1212

@@ -98,13 +98,11 @@ export function QuartileTable({
9898
className={`fr-input ${common.numericInput}`}
9999
disabled={disabled}
100100
inputMode="decimal"
101-
onBlur={() => {
102-
const current = q.threshold ?? "";
103-
const padded = padDecimalToTwo(current);
104-
if (padded !== current) {
105-
onQuartileChange(i, "threshold", padded);
106-
}
107-
}}
101+
onBlur={() =>
102+
padDecimalOnBlur(q.threshold ?? "", (v) =>
103+
onQuartileChange(i, "threshold", v),
104+
)
105+
}
108106
onChange={(e) =>
109107
onQuartileChange(i, "threshold", e.target.value)
110108
}

packages/app/src/modules/declaration-remuneration/steps/step5/CategoryForm.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import type {
1818
EmployeeCategoryRow,
1919
EmployeeCategorySubmitData,
2020
} from "~/modules/declaration-remuneration/types";
21-
import { padDecimalToTwo } from "~/modules/domain";
21+
import { padDecimalOnBlur } from "~/modules/domain";
2222
import { useZodForm } from "~/modules/shared/useZodForm";
2323
import stepStyles from "../Step5EmployeeCategories.module.scss";
2424
import { CategoryDataTable } from "./CategoryDataTable";
@@ -160,12 +160,13 @@ export function CategoryForm({
160160
function handleDecimalBlur(index: number, field: keyof EmployeeCategory) {
161161
return () => {
162162
const formField = field as Exclude<keyof EmployeeCategory, "id">;
163-
const current = form.getValues(`categories.${index}.${formField}`);
164-
const padded = padDecimalToTwo(current);
165-
if (padded !== current) {
166-
form.setValue(`categories.${index}.${formField}`, padded);
167-
setSaved(false);
168-
}
163+
padDecimalOnBlur(
164+
form.getValues(`categories.${index}.${formField}`),
165+
(padded) => {
166+
form.setValue(`categories.${index}.${formField}`, padded);
167+
setSaved(false);
168+
},
169+
);
169170
};
170171
}
171172

packages/app/src/modules/domain/__tests__/number.test.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { describe, expect, it } from "vitest";
1+
import { describe, expect, it, vi } from "vitest";
22

33
import {
44
displayDecimal,
55
normalizeDecimalInput,
6+
padDecimalOnBlur,
67
padDecimalToTwo,
78
parseNumber,
89
} from "../shared/number";
@@ -98,3 +99,35 @@ describe("padDecimalToTwo", () => {
9899
expect(padDecimalToTwo("abc")).toBe("abc");
99100
});
100101
});
102+
103+
describe("padDecimalOnBlur", () => {
104+
it("calls the setter with the padded value when padding changes it", () => {
105+
const setter = vi.fn();
106+
padDecimalOnBlur("100", setter);
107+
expect(setter).toHaveBeenCalledWith("100.00");
108+
});
109+
110+
it("calls the setter when only a trailing zero is missing", () => {
111+
const setter = vi.fn();
112+
padDecimalOnBlur("100.5", setter);
113+
expect(setter).toHaveBeenCalledWith("100.50");
114+
});
115+
116+
it("does not call the setter when the value is already padded", () => {
117+
const setter = vi.fn();
118+
padDecimalOnBlur("100.50", setter);
119+
expect(setter).not.toHaveBeenCalled();
120+
});
121+
122+
it("does not call the setter on an empty value", () => {
123+
const setter = vi.fn();
124+
padDecimalOnBlur("", setter);
125+
expect(setter).not.toHaveBeenCalled();
126+
});
127+
128+
it("does not call the setter on a non-numeric value", () => {
129+
const setter = vi.fn();
130+
padDecimalOnBlur("abc", setter);
131+
expect(setter).not.toHaveBeenCalled();
132+
});
133+
});

packages/app/src/modules/domain/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export {
4949
displayDecimal,
5050
displayInputDecimal,
5151
normalizeDecimalInput,
52+
padDecimalOnBlur,
5253
padDecimalToTwo,
5354
parseNumber,
5455
} from "./shared/number";

packages/app/src/modules/domain/shared/number.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,16 @@ export function padDecimalToTwo(value: string): string {
7777
if (Number.isNaN(n)) return value;
7878
return n.toFixed(2);
7979
}
80+
81+
/**
82+
* Blur handler for decimal inputs: pad the value to two fraction digits and,
83+
* if the result differs from the original, hand it back to the setter.
84+
* Callers keep the value change out of their reducer when nothing needs updating.
85+
*/
86+
export function padDecimalOnBlur(
87+
value: string,
88+
setter: (padded: string) => void,
89+
): void {
90+
const padded = padDecimalToTwo(value);
91+
if (padded !== value) setter(padded);
92+
}

0 commit comments

Comments
 (0)