Skip to content

Commit b94f053

Browse files
Merge branch 'main' into ken/results-counter
2 parents ca49d6e + 513b1f4 commit b94f053

File tree

3 files changed

+56
-37
lines changed

3 files changed

+56
-37
lines changed

frontend/app/routes/estimator/step-income.tsx

+15-15
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ export async function loader({ context, params, request }: Route.LoaderArgs) {
4949
}
5050

5151
export async function action({ context, request }: Route.ActionArgs) {
52-
const { lang } = await getTranslation(request, handle.i18nNamespace);
5352
const formData = await request.formData();
5453
const action = formData.get('action');
5554
const isMarried = context.session.estimator?.maritalStatus === 'married-or-common-law';
@@ -59,7 +58,7 @@ export async function action({ context, request }: Route.ActionArgs) {
5958
throw i18nRedirect('routes/estimator/step-marital-status.tsx', request);
6059
}
6160
case 'next': {
62-
const result = processIncome(formData, isMarried, lang);
61+
const result = processIncome(formData, isMarried);
6362

6463
if (result.errors) {
6564
return data({ errors: result.errors }, { status: 400 });
@@ -72,15 +71,15 @@ export async function action({ context, request }: Route.ActionArgs) {
7271
}
7372
}
7473

75-
function processIncome(formData: FormData, isMarried: boolean, lang: Language) {
74+
function processIncome(formData: FormData, isMarried: boolean) {
7675
const positiveDecimal = new RegExp(/^\d*(\.\d\d?)?$/);
7776

7877
const personIncomeSchema = v.pipe(
7978
v.object({
8079
netIncome: v.pipe(
8180
v.string('net-income.error.required'),
8281
v.nonEmpty('net-income.error.required'),
83-
v.transform((input) => removeNumericFormatting(input, lang)),
82+
v.transform((input) => removeNumericFormatting(input)),
8483
v.regex(positiveDecimal, 'net-income.error.invalid'),
8584
v.transform(Number),
8685
v.number('net-income.error.invalid'),
@@ -89,23 +88,23 @@ function processIncome(formData: FormData, isMarried: boolean, lang: Language) {
8988
workingIncome: v.pipe(
9089
v.string('working-income.error.required'),
9190
v.nonEmpty('working-income.error.required'),
92-
v.transform((input) => removeNumericFormatting(input, lang)),
91+
v.transform((input) => removeNumericFormatting(input)),
9392
v.regex(positiveDecimal, 'working-income.error.invalid'),
9493
v.transform(Number),
9594
v.number('working-income.error.invalid'),
9695
v.minValue(0, 'working-income.error.invalid'),
9796
),
9897
claimedIncome: v.pipe(
9998
v.optional(v.string(), '0'),
100-
v.transform((input) => removeNumericFormatting(input, lang)),
99+
v.transform((input) => removeNumericFormatting(input)),
101100
v.regex(positiveDecimal, 'claimed-income.error.invalid'),
102101
v.transform(Number),
103102
v.number('claimed-income.error.invalid'),
104103
v.minValue(0, 'claimed-income.error.invalid'),
105104
),
106105
claimedRepayment: v.pipe(
107106
v.optional(v.string(), '0'),
108-
v.transform((input) => removeNumericFormatting(input, lang)),
107+
v.transform((input) => removeNumericFormatting(input)),
109108
v.regex(positiveDecimal, 'claimed-repayment.error.invalid'),
110109
v.transform(Number),
111110
v.number('claimed-repayment.error.invalid'),
@@ -198,7 +197,8 @@ export default function StepIncome({ actionData, loaderData, matches, params }:
198197
</div>
199198
}
200199
defaultValue={
201-
loaderData.formValues?.individualIncome.netIncome ?? previousFormValues.get('income:individual-net-income')
200+
loaderData.formValues?.individualIncome.netIncome ??
201+
removeNumericFormatting(previousFormValues.get('income:individual-net-income'))
202202
}
203203
errorMessage={
204204
errors?.nested?.['individualIncome.netIncome']?.at(0) ? (
@@ -226,7 +226,7 @@ export default function StepIncome({ actionData, loaderData, matches, params }:
226226
}
227227
defaultValue={
228228
(loaderData.formValues?.kind === 'married' ? loaderData.formValues.partnerIncome.netIncome : undefined) ??
229-
previousFormValues.get('income:partner-net-income')
229+
removeNumericFormatting(previousFormValues.get('income:partner-net-income'))
230230
}
231231
errorMessage={
232232
errors?.nested?.['partnerIncome.netIncome']?.at(0) ? (
@@ -264,7 +264,7 @@ export default function StepIncome({ actionData, loaderData, matches, params }:
264264
}
265265
defaultValue={
266266
loaderData.formValues?.individualIncome.workingIncome ??
267-
previousFormValues.get('income:individual-working-income')
267+
removeNumericFormatting(previousFormValues.get('income:individual-working-income'))
268268
}
269269
errorMessage={
270270
errors?.nested?.['individualIncome.workingIncome']?.at(0) ? (
@@ -303,7 +303,7 @@ export default function StepIncome({ actionData, loaderData, matches, params }:
303303
}
304304
defaultValue={
305305
(loaderData.formValues?.kind === 'married' ? loaderData.formValues.partnerIncome.workingIncome : undefined) ??
306-
previousFormValues.get('income:partner-working-income')
306+
removeNumericFormatting(previousFormValues.get('income:partner-working-income'))
307307
}
308308
errorMessage={
309309
errors?.nested?.['partnerIncome.workingIncome']?.at(0) ? (
@@ -340,7 +340,7 @@ export default function StepIncome({ actionData, loaderData, matches, params }:
340340
}
341341
defaultValue={
342342
loaderData.formValues?.individualIncome.claimedIncome ??
343-
previousFormValues.get('income:individual-claimed-income')
343+
removeNumericFormatting(previousFormValues.get('income:individual-claimed-income'))
344344
}
345345
errorMessage={
346346
errors?.nested?.['individualIncome.claimedIncome']?.at(0) ? (
@@ -375,7 +375,7 @@ export default function StepIncome({ actionData, loaderData, matches, params }:
375375
}
376376
defaultValue={
377377
loaderData.formValues?.individualIncome.claimedRepayment ??
378-
previousFormValues.get('income:individual-claimed-repayment')
378+
removeNumericFormatting(previousFormValues.get('income:individual-claimed-repayment'))
379379
}
380380
errorMessage={
381381
errors?.nested?.['individualIncome.claimedRepayment']?.at(0) ? (
@@ -411,7 +411,7 @@ export default function StepIncome({ actionData, loaderData, matches, params }:
411411
}
412412
defaultValue={
413413
(loaderData.formValues?.kind === 'married' ? loaderData.formValues.partnerIncome.claimedIncome : undefined) ??
414-
previousFormValues.get('income:partner-claimed-income')
414+
removeNumericFormatting(previousFormValues.get('income:partner-claimed-income'))
415415
}
416416
errorMessage={
417417
errors?.nested?.['partnerIncome.claimedIncome']?.at(0) ? (
@@ -449,7 +449,7 @@ export default function StepIncome({ actionData, loaderData, matches, params }:
449449
defaultValue={
450450
(loaderData.formValues?.kind === 'married'
451451
? loaderData.formValues.partnerIncome.claimedRepayment
452-
: undefined) ?? previousFormValues.get('income:partner-claimed-repayment')
452+
: undefined) ?? removeNumericFormatting(previousFormValues.get('income:partner-claimed-repayment'))
453453
}
454454
errorMessage={
455455
errors?.nested?.['partnerIncome.claimedRepayment']?.at(0) ? (

frontend/app/utils/string-utils.ts

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
/**
22
* Strips formatting from a string representing a formatted decimal
33
* @param input string represenation of a formatted decimal (examples: en:"1,234.56", fr:"1 234,56")
4-
* @param lang Format language (en or fr)
54
* @returns string representation of the decimal without formatting (examples: "1234.56")
65
*/
7-
export function removeNumericFormatting(input: string, lang: Language): string {
8-
switch (lang) {
9-
case 'en': {
10-
const output = input.replaceAll(',', '');
11-
return output;
12-
}
13-
case 'fr': {
14-
const output = input.replaceAll(' ', '').replaceAll(',', '.');
15-
return output;
16-
}
6+
export function removeNumericFormatting(input: string | undefined): string {
7+
if (input === undefined) return '';
8+
9+
const isFrench = input.includes(' ') || input.lastIndexOf(',') >= input.length - 3;
10+
const isEnglish = input.indexOf(',') < input.length - 2 || input.lastIndexOf('.') >= input.length - 3;
11+
12+
if (isFrench) {
13+
const output = input.replaceAll(' ', '').replaceAll(',', '.');
14+
return output;
1715
}
16+
if (isEnglish) {
17+
const output = input.replaceAll(',', '');
18+
return output;
19+
}
20+
21+
return input;
1822
}
1923

2024
/**

frontend/tests/utils/string-utils.test.ts

+26-11
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,33 @@ describe('string-utils', () => {
1717
});
1818

1919
it.each([
20-
{ input: '.00', output: '.00', lang: 'en' },
21-
{ input: '0.00', output: '0.00', lang: 'en' },
22-
{ input: '1,234.56', output: '1234.56', lang: 'en' },
23-
{ input: '123.56', output: '123.56', lang: 'en' },
24-
{ input: ',00', output: '.00', lang: 'fr' },
25-
{ input: '0,00', output: '0.00', lang: 'fr' },
26-
{ input: '1 234,56', output: '1234.56', lang: 'fr' },
27-
{ input: '123,56', output: '123.56', lang: 'fr' },
20+
{ input: '.00', output: '.00' },
21+
{ input: '0.00', output: '0.00' },
22+
{ input: '1,234.56', output: '1234.56' },
23+
{ input: '123.56', output: '123.56' },
24+
{ input: ',00', output: '.00' },
25+
{ input: '0,00', output: '0.00' },
26+
{ input: '1 234,56', output: '1234.56' },
27+
{ input: '123,56', output: '123.56' },
28+
{ input: '1 234', output: '1234' },
29+
{ input: '1,234', output: '1234' },
30+
{ input: '1,234,567', output: '1234567' },
31+
{ input: '1 234 567', output: '1234567' },
32+
{ input: '1', output: '1' },
33+
{ input: '12', output: '12' },
34+
{ input: '123', output: '123' },
35+
{ input: '1.1', output: '1.1' },
36+
{ input: '1,1', output: '1.1' },
37+
{ input: '1,12', output: '1.12' },
38+
{ input: '1.12', output: '1.12' },
39+
{ input: '123.12', output: '123.12' },
40+
{ input: '123,12', output: '123.12' },
41+
{ input: '1,234.12', output: '1234.12' },
42+
{ input: '1 234,12', output: '1234.12' },
2843
])(
29-
'removeNumericFormatting should remove formatting from a formatted decimal string representation',
30-
({ input, lang, output }) => {
31-
const str = removeNumericFormatting(input, lang as Language);
44+
'removeNumericFormatting should remove formatting from a formatted decimal string representation ($input)',
45+
({ input, output }) => {
46+
const str = removeNumericFormatting(input);
3247
expect(str).toBe(output);
3348
},
3449
);

0 commit comments

Comments
 (0)