Skip to content
Open
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
1 change: 1 addition & 0 deletions src/components/CurrencyListContextProvider/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const defaultCurrencyListStateContextValue: CurrencyListStateContextType = {
const defaultCurrencyListActionsContextValue: CurrencyListActionsContextType = {
getCurrencySymbol: () => undefined,
getCurrencyDecimals: () => 2,
convertToDisplayString: () => '',
};

export {defaultCurrencyListStateContextValue, defaultCurrencyListActionsContextValue};
39 changes: 31 additions & 8 deletions src/components/CurrencyListContextProvider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import React, {createContext, useCallback, useContext, useMemo, useRef} from 'react';
import React, {createContext, useCallback, useContext, useMemo} from 'react';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import {convertToFrontendAmountAsInteger} from '@libs/CurrencyUtils';
import {format} from '@libs/NumberFormatUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {CurrencyList} from '@src/types/onyx';
Expand All @@ -12,13 +15,14 @@ const CurrencyListActionsContext = createContext<CurrencyListActionsContextType>

function CurrencyListContextProvider({children}: React.PropsWithChildren) {
const [currencyList = getEmptyObject<CurrencyList>()] = useOnyx(ONYXKEYS.CURRENCY_LIST);
const {preferredLocale} = useLocalize();

const currencyListRef = useRef(currencyList);
currencyListRef.current = currencyList;

const getCurrencySymbol = useCallback((currencyCode: string): string | undefined => {
return currencyListRef.current[currencyCode]?.symbol;
}, []);
const getCurrencySymbol = useCallback(
(currencyCode: string): string | undefined => {
return currencyList[currencyCode]?.symbol;
},
[currencyList],
);

const getCurrencyDecimals = useCallback(
(currencyCode: string | undefined): number => {
Expand All @@ -28,6 +32,24 @@ function CurrencyListContextProvider({children}: React.PropsWithChildren) {
[currencyList],
);

const convertToDisplayString = useCallback(
(amountInCents: number, currencyCode: string): string => {
const decimals = getCurrencyDecimals(currencyCode);
const convertedAmount = convertToFrontendAmountAsInteger(amountInCents, decimals);
return format(preferredLocale, convertedAmount, {
style: 'currency',
currency: currencyCode,

// We are forcing the number of decimals because we override the default number of decimals in the backend for some currencies
// See: https://github.com/Expensify/PHP-Libs/pull/834
minimumFractionDigits: decimals,
// For currencies that have decimal places > 2, floor to 2 instead as we don't support more than 2 decimal places.
maximumFractionDigits: 2,
});
},
[getCurrencyDecimals, preferredLocale],
);

const stateValue = useMemo<CurrencyListStateContextType>(
() => ({
currencyList,
Expand All @@ -39,8 +61,9 @@ function CurrencyListContextProvider({children}: React.PropsWithChildren) {
() => ({
getCurrencySymbol,
getCurrencyDecimals,
convertToDisplayString,
}),
[getCurrencySymbol, getCurrencyDecimals],
[getCurrencySymbol, getCurrencyDecimals, convertToDisplayString],
);

return (
Expand Down
3 changes: 3 additions & 0 deletions src/components/CurrencyListContextProvider/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ type CurrencyListActionsContextType = {

/** Function to get number of digits after the decimal separator for a specific currency */
getCurrencyDecimals: (currencyCode: string | undefined) => number;

/** Function to convert amount in cents to display string based on the currency and locale */
convertToDisplayString: (amount: number, currencyCode: string) => string;
};

export type {CurrencyListStateContextType, CurrencyListActionsContextType};
Loading