From e9e499179932e4e6d675366b68797ee753e4ebfc Mon Sep 17 00:00:00 2001 From: Gabriel Garcia Date: Fri, 30 Jan 2026 19:57:29 +0100 Subject: [PATCH 1/7] fix(cost-calculator) - fix currency --- src/flows/ContractorOnboarding/api.ts | 2 +- .../EstimationResults/EstimationResults.tsx | 70 +++++++++---------- .../SummaryResults/SummaryResults.tsx | 8 +-- .../tests/EstimationResults.test.tsx | 14 ++-- src/lib/__tests__/utils.test.ts | 24 +++++++ src/lib/utils.ts | 11 +-- 6 files changed, 77 insertions(+), 52 deletions(-) diff --git a/src/flows/ContractorOnboarding/api.ts b/src/flows/ContractorOnboarding/api.ts index 7c33b5813..a84476902 100644 --- a/src/flows/ContractorOnboarding/api.ts +++ b/src/flows/ContractorOnboarding/api.ts @@ -287,7 +287,7 @@ export const useContractorSubscriptionSchemaField = ( if (opts.price.amount) { formattedPrice = formatCurrency( opts.price.amount, - opts.currency.symbol, + opts.currency.code, ); } const product = opts.product; diff --git a/src/flows/CostCalculator/EstimationResults/EstimationResults.tsx b/src/flows/CostCalculator/EstimationResults/EstimationResults.tsx index 4e430e39b..fd20105a1 100644 --- a/src/flows/CostCalculator/EstimationResults/EstimationResults.tsx +++ b/src/flows/CostCalculator/EstimationResults/EstimationResults.tsx @@ -614,7 +614,7 @@ export const EstimationResults = ({ const formattedSalary = formatCurrency( estimation.regional_currency_costs.annual_gross_salary, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ); return ( @@ -642,16 +642,16 @@ export const EstimationResults = ({ ? [ formatCurrency( estimation.regional_currency_costs.monthly_total, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), formatCurrency( estimation.employer_currency_costs.monthly_total, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), ] : formatCurrency( estimation.regional_currency_costs.monthly_total, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ) } > @@ -661,11 +661,11 @@ export const EstimationResults = ({ label: 'Gross monthly salary', regionalAmount: formatCurrency( estimation.regional_currency_costs.monthly_gross_salary, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( estimation.employer_currency_costs.monthly_gross_salary, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), zendeskId: zendeskArticles.extraPayments.toString(), tooltip: @@ -676,12 +676,12 @@ export const EstimationResults = ({ regionalAmount: formatCurrency( estimation.regional_currency_costs .monthly_contributions_total, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( estimation.employer_currency_costs .monthly_contributions_total, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), children: estimation.employer_currency_costs.monthly_contributions_breakdown?.map( @@ -691,11 +691,11 @@ export const EstimationResults = ({ regionalAmount: formatCurrency( estimation.regional_currency_costs .monthly_contributions_breakdown?.[index]?.amount, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( item.amount, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), zendeskId: item.zendesk_article_id || undefined, tooltip: item.description || undefined, @@ -707,11 +707,11 @@ export const EstimationResults = ({ label: 'Benefits', regionalAmount: formatCurrency( estimation.regional_currency_costs.monthly_benefits_total, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( estimation.employer_currency_costs.monthly_benefits_total, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), children: estimation.employer_currency_costs.monthly_benefits_breakdown?.map( @@ -720,11 +720,11 @@ export const EstimationResults = ({ regionalAmount: formatCurrency( estimation.regional_currency_costs .monthly_benefits_breakdown?.[index]?.amount, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( item.amount, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), zendeskId: item.zendesk_article_id || undefined, tooltip: item.description || undefined, @@ -738,12 +738,12 @@ export const EstimationResults = ({ regionalAmount: formatCurrency( estimation.regional_currency_costs .monthly_management_fee, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( estimation.employer_currency_costs .monthly_management_fee, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), tooltip: 'Discounts may be available based on your commitment and team size. Speak to your account or customer success manager to learn more.', @@ -763,16 +763,16 @@ export const EstimationResults = ({ ? [ formatCurrency( estimation.regional_currency_costs.annual_total, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), formatCurrency( estimation.employer_currency_costs.annual_total, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), ] : formatCurrency( estimation.regional_currency_costs.annual_total, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ) } > @@ -783,22 +783,22 @@ export const EstimationResults = ({ dataSelector: 'annual-gross-salary', regionalAmount: formatCurrency( estimation.regional_currency_costs.annual_gross_salary, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( estimation.employer_currency_costs.annual_gross_salary, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), }, { label: 'Mandatory employer costs', regionalAmount: formatCurrency( estimation.regional_currency_costs.annual_contributions_total, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( estimation.employer_currency_costs.annual_contributions_total, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), children: estimation.employer_currency_costs.annual_contributions_breakdown?.map( @@ -807,11 +807,11 @@ export const EstimationResults = ({ regionalAmount: formatCurrency( estimation.regional_currency_costs .annual_contributions_breakdown?.[index]?.amount, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( item.amount, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), zendeskId: item.zendesk_article_id || undefined, tooltip: item.description || undefined, @@ -822,11 +822,11 @@ export const EstimationResults = ({ label: 'Benefits', regionalAmount: formatCurrency( estimation.regional_currency_costs.annual_benefits_total, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( estimation.employer_currency_costs.annual_benefits_total, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), children: estimation.employer_currency_costs.annual_benefits_breakdown?.map( @@ -835,11 +835,11 @@ export const EstimationResults = ({ regionalAmount: formatCurrency( estimation.regional_currency_costs .annual_benefits_breakdown?.[index]?.amount, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( item.amount, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), zendeskId: item.zendesk_article_id || undefined, tooltip: item.description || undefined, @@ -851,12 +851,12 @@ export const EstimationResults = ({ regionalAmount: formatCurrency( estimation.regional_currency_costs .extra_statutory_payments_total, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( estimation.employer_currency_costs .extra_statutory_payments_total, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), children: estimation.employer_currency_costs.extra_statutory_payments_breakdown?.map( @@ -865,11 +865,11 @@ export const EstimationResults = ({ regionalAmount: formatCurrency( estimation.regional_currency_costs .extra_statutory_payments_breakdown?.[index]?.amount, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( item.amount, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), zendeskId: item.zendesk_article_id || undefined, tooltip: item.description || undefined, @@ -883,12 +883,12 @@ export const EstimationResults = ({ regionalAmount: formatCurrency( estimation.regional_currency_costs .annual_management_fee, - estimation.regional_currency_costs.currency.symbol, + estimation.regional_currency_costs.currency.code, ), employerAmount: formatCurrency( estimation.employer_currency_costs .annual_management_fee, - estimation.employer_currency_costs.currency.symbol, + estimation.employer_currency_costs.currency.code, ), tooltip: 'Discounts may be available based on your commitment and team size. Speak to your account or customer success manager to learn more.', diff --git a/src/flows/CostCalculator/SummaryResults/SummaryResults.tsx b/src/flows/CostCalculator/SummaryResults/SummaryResults.tsx index f23b5e9a2..5197f46b0 100644 --- a/src/flows/CostCalculator/SummaryResults/SummaryResults.tsx +++ b/src/flows/CostCalculator/SummaryResults/SummaryResults.tsx @@ -49,8 +49,8 @@ const useSummaryResults = (estimations: CostCalculatorEstimation[]) => { const groupedCostsPerCountry = Object.values(costsPerCountry).map( ({ country, monthlyTotal, annualTotal }) => ({ country, - monthlyCost: formatCurrency(monthlyTotal, currency.symbol), - annualCost: formatCurrency(annualTotal, currency.symbol), + monthlyCost: formatCurrency(monthlyTotal, currency.code), + annualCost: formatCurrency(annualTotal, currency.code), }), ); @@ -59,13 +59,13 @@ const useSummaryResults = (estimations: CostCalculatorEstimation[]) => { estimations.reduce((acc, estimation) => { return acc + estimation.employer_currency_costs.monthly_total; }, 0), - currency.symbol, + currency.code, ), annualTotal: formatCurrency( estimations.reduce((acc, estimation) => { return acc + estimation.employer_currency_costs.annual_total; }, 0), - currency.symbol, + currency.code, ), }; return { currency, costsPerCountry: groupedCostsPerCountry, employeesCost }; diff --git a/src/flows/CostCalculator/tests/EstimationResults.test.tsx b/src/flows/CostCalculator/tests/EstimationResults.test.tsx index f2db04b7d..f58d557f1 100644 --- a/src/flows/CostCalculator/tests/EstimationResults.test.tsx +++ b/src/flows/CostCalculator/tests/EstimationResults.test.tsx @@ -159,7 +159,7 @@ describe('EstimationResults', () => { // Check if annual gross salary is rendered const formattedSalary = formatCurrency( mockEstimation.regional_currency_costs.annual_gross_salary, - mockEstimation.regional_currency_costs.currency.symbol, + mockEstimation.regional_currency_costs.currency.code, ); const salaryContainer = screen.getByTestId( @@ -209,11 +209,11 @@ describe('EstimationResults', () => { // Check monthly total amounts const monthlyRegionalTotal = formatCurrency( mockEstimation.regional_currency_costs.monthly_total, - mockEstimation.regional_currency_costs.currency.symbol, + mockEstimation.regional_currency_costs.currency.code, ); const monthlyEmployerTotal = formatCurrency( mockEstimation.employer_currency_costs.monthly_total, - mockEstimation.employer_currency_costs.currency.symbol, + mockEstimation.employer_currency_costs.currency.code, ); expect(screen.getByText(monthlyRegionalTotal)).toBeInTheDocument(); @@ -284,12 +284,12 @@ describe('EstimationResults', () => { const expectedRegionalAmount = formatCurrency( mockEstimation.regional_currency_costs.monthly_benefits_breakdown[0] .amount, - mockEstimation.regional_currency_costs.currency.symbol, + mockEstimation.regional_currency_costs.currency.code, ); const expectedEmployerAmount = formatCurrency( mockEstimation.employer_currency_costs.monthly_benefits_breakdown[0] .amount, - mockEstimation.employer_currency_costs.currency.symbol, + mockEstimation.employer_currency_costs.currency.code, ); // Find the amounts in the document @@ -299,11 +299,11 @@ describe('EstimationResults', () => { // Also verify the total core benefits const totalRegionalAmount = formatCurrency( mockEstimation.regional_currency_costs.monthly_benefits_total, - mockEstimation.regional_currency_costs.currency.symbol, + mockEstimation.regional_currency_costs.currency.code, ); const totalEmployerAmount = formatCurrency( mockEstimation.employer_currency_costs.monthly_benefits_total, - mockEstimation.employer_currency_costs.currency.symbol, + mockEstimation.employer_currency_costs.currency.code, ); expect(screen.getByText(totalRegionalAmount)).toBeInTheDocument(); diff --git a/src/lib/__tests__/utils.test.ts b/src/lib/__tests__/utils.test.ts index 82e59f33b..2a4c9c8ff 100644 --- a/src/lib/__tests__/utils.test.ts +++ b/src/lib/__tests__/utils.test.ts @@ -1,5 +1,6 @@ import { JSFFields } from '@/src/types/remoteFlows'; import { + formatCurrency, prettifyFormValues, sanitizeHtml, sanitizeHtmlWithImageErrorHandling, @@ -350,4 +351,27 @@ describe('utils lib', () => { }); }); }); + + describe('formatCurrency', () => { + it('should return "-" for undefined or null amount', () => { + expect(formatCurrency(null)).toBe('-'); + expect(formatCurrency(undefined)).toBe('-'); + }); + + it('should format amount in EUR by default', () => { + expect(formatCurrency(5000)).toBe('€50.00'); + }); + + it('should format amount in specified currency', () => { + expect(formatCurrency(10000, 'USD')).toBe('$100.00'); + }); + + it('should format amount with currency code', () => { + expect(formatCurrency(10000, 'ARS')).toBe('ARS\u00A0100.00'); + }); + + it('should handle zero amount', () => { + expect(formatCurrency(0, 'USD')).toBe('$0.00'); + }); + }); }); diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 432f18005..e51aa63e3 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -14,7 +14,7 @@ export function cn(...inputs: ClassValue[]) { export function formatCurrency( amount: number | undefined | null, - symbol = '€', + currencyCode = 'EUR', ): string { if (amount == null) { return '-'; @@ -22,10 +22,11 @@ export function formatCurrency( const value = amount / 100; - return `${symbol}${value.toLocaleString('en-US', { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - })}`; + return new Intl.NumberFormat('en', { + style: 'currency', + currency: currencyCode, + currencyDisplay: 'symbol', + }).format(value); } type YupError = Pick & { From 8f9ff08d461148a62a122d702f0a172432e97fce Mon Sep 17 00:00:00 2001 From: Gabriel Garcia Date: Fri, 30 Jan 2026 20:20:41 +0100 Subject: [PATCH 2/7] fix e2e test --- example/e2e/annual-gross-salary.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/e2e/annual-gross-salary.spec.ts b/example/e2e/annual-gross-salary.spec.ts index 4e806832c..42927a661 100644 --- a/example/e2e/annual-gross-salary.spec.ts +++ b/example/e2e/annual-gross-salary.spec.ts @@ -22,7 +22,7 @@ test.describe('annual gross salary', () => { // Using getByText for static text + regex for dynamic part const headerAmount = page.getByText( - /Employee annual gross salary: kr\d+\.\d\d/, + /Employee annual gross salary: SEK\d+\.\d\d/, ); await expect(headerAmount).toBeVisible(); }); From 1fac5e2bdef2342997c7a1297a3a1da1feea7131 Mon Sep 17 00:00:00 2001 From: Gabriel Garcia Date: Fri, 30 Jan 2026 20:27:42 +0100 Subject: [PATCH 3/7] fix spec --- example/e2e/hiring-budget.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/e2e/hiring-budget.spec.ts b/example/e2e/hiring-budget.spec.ts index fe2c3944f..a58489ca8 100644 --- a/example/e2e/hiring-budget.spec.ts +++ b/example/e2e/hiring-budget.spec.ts @@ -19,7 +19,7 @@ test.describe('hiring budget', () => { }); const headerAmount = page.getByText( - /Employee annual gross salary: kr\d{1,3}(,\d{3})*\.\d{2}/, + /Employee annual gross salary: SEK\d{1,3}(,\d{3})*\.\d{2}/, ); await expect(headerAmount).toBeVisible(); From ebe817f9a352fb39b2e5e25785c633fb2103e5a1 Mon Sep 17 00:00:00 2001 From: Gabriel Garcia Date: Fri, 30 Jan 2026 20:42:06 +0100 Subject: [PATCH 4/7] fix spaces --- example/e2e/annual-gross-salary.spec.ts | 2 +- example/e2e/hiring-budget.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/e2e/annual-gross-salary.spec.ts b/example/e2e/annual-gross-salary.spec.ts index 42927a661..e83d57b3a 100644 --- a/example/e2e/annual-gross-salary.spec.ts +++ b/example/e2e/annual-gross-salary.spec.ts @@ -22,7 +22,7 @@ test.describe('annual gross salary', () => { // Using getByText for static text + regex for dynamic part const headerAmount = page.getByText( - /Employee annual gross salary: SEK\d+\.\d\d/, + /Employee annual gross salary: SEK\s\d+\.\d\d/, ); await expect(headerAmount).toBeVisible(); }); diff --git a/example/e2e/hiring-budget.spec.ts b/example/e2e/hiring-budget.spec.ts index a58489ca8..274069963 100644 --- a/example/e2e/hiring-budget.spec.ts +++ b/example/e2e/hiring-budget.spec.ts @@ -19,7 +19,7 @@ test.describe('hiring budget', () => { }); const headerAmount = page.getByText( - /Employee annual gross salary: SEK\d{1,3}(,\d{3})*\.\d{2}/, + /Employee annual gross salary: SEK\s\d+\.\d\d/, ); await expect(headerAmount).toBeVisible(); From 20c8020313ed0de984ed5c0983dae238c47c527c Mon Sep 17 00:00:00 2001 From: Gabriel Garcia Date: Fri, 30 Jan 2026 21:04:47 +0100 Subject: [PATCH 5/7] fix spacing --- example/e2e/hiring-budget.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/e2e/hiring-budget.spec.ts b/example/e2e/hiring-budget.spec.ts index 274069963..124975941 100644 --- a/example/e2e/hiring-budget.spec.ts +++ b/example/e2e/hiring-budget.spec.ts @@ -19,7 +19,7 @@ test.describe('hiring budget', () => { }); const headerAmount = page.getByText( - /Employee annual gross salary: SEK\s\d+\.\d\d/, + /Employee annual gross salary: SEK\s\d{1,3}(,\d{3})*\.\d{2}/, ); await expect(headerAmount).toBeVisible(); From 754a0b4bd535a9c31e40f020ffd90f22a8163089 Mon Sep 17 00:00:00 2001 From: Gabriel Garcia Date: Fri, 30 Jan 2026 21:07:30 +0100 Subject: [PATCH 6/7] fix number --- example/e2e/hiring-budget.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/e2e/hiring-budget.spec.ts b/example/e2e/hiring-budget.spec.ts index 124975941..1338b276a 100644 --- a/example/e2e/hiring-budget.spec.ts +++ b/example/e2e/hiring-budget.spec.ts @@ -19,7 +19,7 @@ test.describe('hiring budget', () => { }); const headerAmount = page.getByText( - /Employee annual gross salary: SEK\s\d{1,3}(,\d{3})*\.\d{2}/, + /Employee annual gross salary: SEK\s[\d,]+\.\d{2}/, ); await expect(headerAmount).toBeVisible(); From 00f8afe842d534cefe008b4c87e92a86d3a8ac05 Mon Sep 17 00:00:00 2001 From: Gabriel Garcia Date: Fri, 30 Jan 2026 21:09:23 +0100 Subject: [PATCH 7/7] fix spacing --- example/e2e/hiring-budget.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/e2e/hiring-budget.spec.ts b/example/e2e/hiring-budget.spec.ts index 1338b276a..124975941 100644 --- a/example/e2e/hiring-budget.spec.ts +++ b/example/e2e/hiring-budget.spec.ts @@ -19,7 +19,7 @@ test.describe('hiring budget', () => { }); const headerAmount = page.getByText( - /Employee annual gross salary: SEK\s[\d,]+\.\d{2}/, + /Employee annual gross salary: SEK\s\d{1,3}(,\d{3})*\.\d{2}/, ); await expect(headerAmount).toBeVisible();