From af54f0734930389f2f76a45cefc8f280969ff1d9 Mon Sep 17 00:00:00 2001 From: Donkie Date: Sat, 16 Sep 2023 14:16:30 +0200 Subject: [PATCH] Client: Number formatting/parsing update Can now use comma or period in any locale and it will handle it correctly. To do this, it now always uses a blank space as a thousands separator to prevent ambiguity with the decimal separator. --- client/src/utils/parsing.tsx | 57 +++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/client/src/utils/parsing.tsx b/client/src/utils/parsing.tsx index 7e59ca3..79f0c72 100644 --- a/client/src/utils/parsing.tsx +++ b/client/src/utils/parsing.tsx @@ -1,17 +1,53 @@ import React from "react"; -// Number formatter that nicely formats numbers with correct decimal separator -export function numberFormatter(value: number | undefined) { - return value ? Number(value).toLocaleString() : ""; +/** + * Insert blankspace thousands separator into a number + * Supports both period or comma as decimal separator + * @param input + * @returns + */ +export function formatNumberWithSpaceSeparator(input: string): string { + const isPeriodDecimalSeparator = input.indexOf(".") > -1; + + const parts = input.split(isPeriodDecimalSeparator ? "." : ","); + + const integerPart = parts[0]; + const decimalPart = parts[1] || ""; + + // Add the thousands separator (blank space) to the integer part + const formattedIntegerPart = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, " "); + + // Combine the formatted integer and decimal parts + const suffix = decimalPart ? (isPeriodDecimalSeparator ? "." : ",") + decimalPart : ""; + const formattedNumber = formattedIntegerPart + suffix; + + return formattedNumber; } -// Number parser that supports both comma and dot as decimal separator +/** + * Number formatter that nicely formats numbers with correct decimal separator based on locale + * Always uses blank space as thousands separator to prevent confusion with the decimal separator + * @param value + * @returns + */ +export function numberFormatter(value: number | undefined): string { + const formattedValue = value + ? Number(value).toLocaleString(undefined, { + useGrouping: false, // Disable thousands separator and do it manually instead so it's always spaces + }) + : ""; + + return formatNumberWithSpaceSeparator(formattedValue); +} + +/** + * Number parser that supports both comma and dot as decimal separator + * @param value + * @returns + */ export function numberParser(value: string | undefined) { // Convert comma to dot - const decimalSeparator = (1.1).toLocaleString().charAt(1); - if (decimalSeparator === ",") { - value = value?.replace(",", "."); - } + value = value?.replace(",", "."); // Remove all non-digit characters value = value?.replace(/[^\d.-]/g, ""); @@ -20,6 +56,11 @@ export function numberParser(value: string | undefined) { return parseFloat(value || "0"); } +/** + * Enrich text with links + * @param text + * @returns + */ export function enrichText(text: string | undefined) { // Regular expression to match URLs const urlRegex =