Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/on 2950 decimal entry foreign language #1072

Merged
merged 3 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion app/src/components/Tabs/Activity/activity-accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import React, { FC, useMemo } from "react";
import { MdModeEditOutline, MdMoreVert } from "react-icons/md";
import { FiTrash2 } from "react-icons/fi";
import { ExtraField, findMethodology, Methodology } from "@/util/form-schema";
import { useParams } from "next/navigation";
import { REGIONALLOCALES } from "@/util/constants";

interface IActivityGroup {
activityData: ActivityValue[];
Expand Down Expand Up @@ -61,6 +63,7 @@ const ActivityAccordion: FC<ActivityAccordionProps> = ({
onEditActivity,
referenceNumber,
}) => {
const { lng } = useParams();
// perform the group by logic when there's more than one activity.
// split the data into groups
// for each table group by the group by field
Expand Down Expand Up @@ -246,7 +249,13 @@ const ActivityAccordion: FC<ActivityAccordionProps> = ({
{parseFloat(activity?.activityData[title])}{" "}
{t(activity?.activityData[title + "-unit"])}
</Td>
<Td>{convertKgToTonnes(activity?.co2eq)}</Td>
<Td>
{convertKgToTonnes(
activity?.co2eq,
null,
REGIONALLOCALES[lng as string],
)}
</Td>
<Td>
<Popover>
<PopoverTrigger>
Expand Down Expand Up @@ -402,6 +411,8 @@ const ActivityAccordion: FC<ActivityAccordionProps> = ({
acc + BigInt(curr.co2eq as bigint),
0n,
),
null,
REGIONALLOCALES[lng as string],
)}{" "}
</Text>
</Box>
Expand Down
8 changes: 8 additions & 0 deletions app/src/components/Tabs/Activity/direct-measure-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import {
MANUAL_INPUT_HIERARCHY,
} from "@/util/form-schema";
import { AddIcon } from "@chakra-ui/icons";
import { useParams } from "next/navigation";
import { REGIONALLOCALES } from "@/util/constants";

interface DirectMeasureTableProps {
t: TFunction;
Expand All @@ -52,6 +54,7 @@ const DirectMeasureTable: FC<DirectMeasureTableProps> = ({
t,
showActivityModal,
}) => {
const { lng } = useParams();
const directMeasure = MANUAL_INPUT_HIERARCHY[referenceNumber as string]
.directMeasure as DirectMeasure;
const extraFields = directMeasure["extra-fields"] as ExtraField[];
Expand Down Expand Up @@ -134,18 +137,21 @@ const DirectMeasureTable: FC<DirectMeasureTableProps> = ({
{convertKgToTonnes(
activity?.activityData?.co2_amount * 1000,
"CO2e",
REGIONALLOCALES[lng as string],
)}
</Td>
<Td isNumeric isTruncated>
{convertKgToTonnes(
activity?.activityData?.n2o_amount * 1000,
"N2O",
REGIONALLOCALES[lng as string],
)}
</Td>
<Td isNumeric isTruncated>
{convertKgToTonnes(
activity?.activityData?.ch4_amount * 1000,
"CH4",
REGIONALLOCALES[lng as string],
)}
</Td>
<Td>
Expand Down Expand Up @@ -292,6 +298,8 @@ const DirectMeasureTable: FC<DirectMeasureTableProps> = ({
acc + BigInt(curr.co2eq as bigint),
0n,
),
null,
REGIONALLOCALES[lng as string],
)}{" "}
</Text>
</Box>
Expand Down
10 changes: 9 additions & 1 deletion app/src/components/Tabs/Activity/emission-data-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import HeadingText from "@/components/heading-text";
import { MdMoreVert } from "react-icons/md";
import { FaNetworkWired } from "react-icons/fa";
import { FiTrash2 } from "react-icons/fi";
import { REGIONALLOCALES } from "@/util/constants";
import { useParams } from "next/navigation";

interface EmissionDataSectionProps {
t: TFunction;
Expand Down Expand Up @@ -118,6 +120,8 @@ const EmissionDataSection = ({
onAddActivityModalOpen();
};

const { lng } = useParams();

const renderSuggestedActivities = () => (
<>
{suggestedActivities.length ? (
Expand Down Expand Up @@ -357,7 +361,11 @@ const EmissionDataSection = ({
fontWeight="semibold"
fontSize="headline.md"
>
{convertKgToTonnes(inventoryValue?.co2eq as bigint)}
{convertKgToTonnes(
inventoryValue?.co2eq as bigint,
null,
REGIONALLOCALES[lng as string],
)}
</Text>
</Box>
</Box>
Expand Down
61 changes: 48 additions & 13 deletions app/src/components/formatted-number-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
NumberInputProps,
} from "@chakra-ui/react";
import { useParams } from "next/navigation";
import { REGIONALLOCALES } from "@/util/constants";

interface FormattedNumberInputProps extends NumberInputProps {
control: Control<any, any>;
Expand All @@ -21,6 +22,7 @@ interface FormattedNumberInputProps extends NumberInputProps {
id?: string;
miniAddon?: boolean;
testId?: string;
localization?: string;
t: Function;
}

Expand Down Expand Up @@ -48,22 +50,41 @@ function FormattedNumberInput({
name,
});

// Format the number according to the locale
const format = (nval: number | string) => {
isaaccodekill marked this conversation as resolved.
Show resolved Hide resolved
let val = parseFloat(nval as string);

const lastItemDot = nval.toString().slice(-1) === ".";
if (isNaN(val)) return "";
return (
new Intl.NumberFormat(lng, {
maximumFractionDigits: 20,
}).format(val) + (lastItemDot ? "." : "")
);
nval = nval.toString();
const locale = REGIONALLOCALES[lng as string] || "en-US"; // Get the user's locale
const decimalSeparator = (1.1).toLocaleString(locale).substring(1, 2); // Detect the decimal separator

// Check if the input ends with a decimal separator

const endsWithSeparator = nval.toString().slice(-1) === decimalSeparator;

// Replace the locale-specific separator with a dot for parsing
const normalizedValue = nval.replace(decimalSeparator, ".");

// Parse the number
const numericValue = parseFloat(normalizedValue);

// If the input is not a valid number, return it as is
if (isNaN(numericValue)) return nval;
isaaccodekill marked this conversation as resolved.
Show resolved Hide resolved

// Format the number part
const formattedNumber = new Intl.NumberFormat(locale, {
maximumFractionDigits: 20,
}).format(numericValue);

// If the input ends with a separator, add it back to the formatted string
return endsWithSeparator
? `${formattedNumber}${decimalSeparator}`
: formattedNumber;
};

// Parse the formatted string into a raw number
const parse = (val: string) => {
const localeDecimalSeparator = (1.1).toLocaleString(lng).substring(1, 2); // Get the decimal separator for the current locale
const localeDecimalSeparator = (1.1)
.toLocaleString(REGIONALLOCALES[lng as string])
.substring(1, 2); // Get the decimal separator for the current locale

const normalizedVal = val.replace(
new RegExp(`[^0-9${localeDecimalSeparator}-]`, "g"),
"",
Expand All @@ -74,6 +95,19 @@ function FormattedNumberInput({
: normalizedNumber.toString();
};

const isCharacterValid = (char: string) => {
const normalizedLocale = REGIONALLOCALES[lng as string] || "en-US"; // Default to en-US
const decimalSeparator = (1.1)
.toLocaleString(normalizedLocale)
.substring(1, 2);

// Build the regex dynamically to include the decimal separator
const validRegex = new RegExp(`^[0-9${decimalSeparator}]$`);

// Check if the character matches the valid regex
return validRegex.test(char);
};

return (
<Controller
control={control}
Expand All @@ -96,12 +130,13 @@ function FormattedNumberInput({
render={({ field }) => (
<InputGroup>
<NumberInput
ste
isDisabled={isDisabled}
value={format(field.value)}
onChange={(valueAsString) => {
const parsedValue = parse(valueAsString);
field.onChange(parsedValue);
field.onChange(valueAsString);
}}
isValidCharacter={isCharacterValid}
onBlur={(e) => {
e.preventDefault();
const parsedValue = parse(e.target.value);
Expand Down
9 changes: 8 additions & 1 deletion app/src/util/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PiPlant, PiTrashLight } from "react-icons/pi";
import { TbBuildingCommunity } from "react-icons/tb";
import { IconBaseProps } from "react-icons";
import { LiaIndustrySolid } from "react-icons/lia";
import { appTheme, SectorColors } from "@/lib/app-theme"; // Import the appTheme
import { SectorColors } from "@/lib/app-theme"; // Import the appTheme

export const maxPopulationYearDifference = 5;

Expand Down Expand Up @@ -136,3 +136,10 @@ export const getSectorByName = (name: string) =>

export const getReferenceNumberByName = (name: keyof ISector) =>
findBy("name", name)?.referenceNumber;

export const REGIONALLOCALES: Record<string, string> = {
es: "es-ES", // Spanish (Spain)
en: "en-US", // English (United States)
pt: "pt-PT", // Portuguese (Portugal)
de: "de-DE", // German (Germany)
};
4 changes: 2 additions & 2 deletions app/src/util/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,9 @@ export function convertKgToKiloTonnes(

export function convertKgToTonnes(
valueInKg: number | Decimal | bigint,
gas?: string,
gas?: string | null,
locale = "en-US",
): string {
const locale = "en-US";
const gasSuffix = gas ? ` ${gas}` : " CO2e";

const kg = toDecimal(valueInKg);
Expand Down
Loading