Skip to content

Commit

Permalink
Merge pull request #539 from JeevanJoshi4434/master
Browse files Browse the repository at this point in the history
Corrected Decimal Number Conversion and addressed bot feedback to correct code format and logic.
  • Loading branch information
al1abb authored Dec 8, 2024
2 parents 2dc0321 + ba9c77b commit 9d99b40
Show file tree
Hide file tree
Showing 4 changed files with 1,108 additions and 15 deletions.
7 changes: 4 additions & 3 deletions contexts/ChargesContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type ChargesContextProps = {
};

export const ChargesContextProvider = ({ children }: ChargesContextProps) => {
const { control, setValue } = useFormContext<InvoiceType>();
const { control, setValue, getValues } = useFormContext<InvoiceType>();

// Form Fields
const itemsArray = useWatch({
Expand Down Expand Up @@ -164,6 +164,7 @@ export const ChargesContextProvider = ({ children }: ChargesContextProps) => {
tax?.amount,
shippingType,
shipping?.cost,
currency,
]);

/**
Expand Down Expand Up @@ -232,9 +233,9 @@ export const ChargesContextProvider = ({ children }: ChargesContextProps) => {
setValue("details.shippingDetails.costType", shippingCostType);

setValue("details.totalAmount", total);

if (totalInWordsSwitch) {
setValue("details.totalAmountInWords", formatPriceToString(total));
setValue("details.totalAmountInWords", formatPriceToString(total, getValues("details.currency")));
} else {
setValue("details.totalAmountInWords", "");
}
Expand Down
87 changes: 75 additions & 12 deletions lib/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { NextResponse } from "next/server";
// Utils
import numberToWords from "number-to-words";

// Currencies
import currenciesDetails from "@/public/assets/data/currencies.json";
import { CurrencyDetails } from "@/types";

/**
* Formats a number with commas and decimal places
*
Expand All @@ -18,33 +22,92 @@ const formatNumberWithCommas = (number: number) => {
});
};

/**
* @param {string} currency - The currency that is currently selected
* @returns {Object} - An object containing the currency details as
* ```
* {
"currency": "United Arab Emirates Dirham",
"decimals": 2,
"beforeDecimal": "Dirham",
"afterDecimal": "Fils"
}
*/
const fetchCurrencyDetails = (currency: string): CurrencyDetails | null => {
const data = currenciesDetails as Record<string, CurrencyDetails>;
const currencyDetails = data[currency];
return currencyDetails || null;
};


/**
* Turns a number into words for invoices
*
* @param {number} price - Number to format
* @returns {string} Number in words
*/
const formatPriceToString = (price: number): string => {
// Split the price into integer and fractional parts (Dollar and Cents)
const integerPart = Math.floor(price);
const fractionalPart = Math.round((price - integerPart) * 100);
const formatPriceToString = (price: number, currency: string): string => {
// Initialize variables
let decimals : number;
let beforeDecimal: string | null = null;
let afterDecimal: string | null = null;

const currencyDetails = fetchCurrencyDetails(currency);

// If currencyDetails is available, use its values, else dynamically set decimals
if (currencyDetails) {
decimals = currencyDetails.decimals;
beforeDecimal = currencyDetails.beforeDecimal;
afterDecimal = currencyDetails.afterDecimal;
} else {
// Dynamically get decimals from the price if currencyDetails is null
const priceString = price.toString();
const decimalIndex = priceString.indexOf('.');
decimals = decimalIndex !== -1 ? priceString.split('.')[1].length : 0;
}

// Ensure the price is rounded to the appropriate decimal places
const roundedPrice = parseFloat(price.toFixed(decimals));

// Split the price into integer and fractional parts
const integerPart = Math.floor(roundedPrice);

const fractionalMultiplier = Math.pow(10, decimals);
const fractionalPart = Math.round((roundedPrice - integerPart) * fractionalMultiplier);

// Convert the integer part to words with capitalized first letter
// Convert the integer part to words with a capitalized first letter
const integerPartInWords = numberToWords
.toWords(integerPart)
.replace(/^\w/, (c) => c.toUpperCase());

// Create the result string without fractional part if it's zero
// Convert fractional part to words
const fractionalPartInWords =
fractionalPart > 0
? numberToWords.toWords(fractionalPart)
: null;

// Handle zero values for both parts
if (integerPart === 0 && fractionalPart === 0) {
return "Zero";
}

// Combine the parts into the final string
let result = integerPartInWords;

// Append fractional part only if it's not zero
if (fractionalPart !== 0) {
result += ` and ${fractionalPart}/100`;
// Check if beforeDecimal is not null
if (beforeDecimal !== null) {
result += ` ${beforeDecimal}`;
}

// Handle the case when both integer and fractional parts are zero
if (integerPart === 0 && fractionalPart === 0) {
return "Zero";
if (fractionalPartInWords) {
// Check if afterDecimal is not null
if (afterDecimal !== null) {
// Concatenate the after decimal and fractional part
result += ` and ${fractionalPartInWords} ${afterDecimal}`;
} else {
// If afterDecimal is null, concatenate the fractional part
result += ` point ${fractionalPartInWords}`;
}
}

return result;
Expand Down
Loading

0 comments on commit 9d99b40

Please sign in to comment.