diff --git a/src/components/LHNOptionsList/OptionRowLHN/OptionRowLHNData.tsx b/src/components/LHNOptionsList/OptionRowLHN/OptionRowLHNData.tsx index c8db8bcea5b4..95f83c1203bf 100644 --- a/src/components/LHNOptionsList/OptionRowLHN/OptionRowLHNData.tsx +++ b/src/components/LHNOptionsList/OptionRowLHN/OptionRowLHNData.tsx @@ -53,7 +53,7 @@ function OptionRowLHNData({ const {currentReportID: currentReportIDValue} = useCurrentReportIDState(); const isReportFocused = isOptionFocused && currentReportIDValue === reportID; const {translate, localeCompare, dateFnsLocale, formatPhoneNumber} = useLocalize(); - const {convertToDisplayString} = useCurrencyListActions(); + const {convertToDisplayString, convertToDisplayStringWithoutCurrency} = useCurrencyListActions(); const {login, accountID: currentUserAccountID} = useCurrentUserPersonalDetails(); const oneTransactionThreadReportID = oneTransactionThreadReport?.reportID; @@ -162,6 +162,7 @@ function OptionRowLHNData({ lastAction, translate, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, isReportArchived, lastActionReport, diff --git a/src/components/Search/FilterComponents/InSelector.tsx b/src/components/Search/FilterComponents/InSelector.tsx index 7f458edfa5ab..35fa8f55985d 100644 --- a/src/components/Search/FilterComponents/InSelector.tsx +++ b/src/components/Search/FilterComponents/InSelector.tsx @@ -4,6 +4,7 @@ import InviteMemberListItem from '@components/SelectionList/ListItem/InviteMembe import SelectionListWithSections from '@components/SelectionList/SelectionListWithSections'; import type {TextInputOptions} from '@components/SelectionList/types'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebouncedState from '@hooks/useDebouncedState'; import useFilteredOptions from '@hooks/useFilteredOptions'; @@ -48,6 +49,7 @@ function getSelectedOptionData(option: Option & Pick): O function InSelector({value = [], selectionListTextInputStyle, selectionListStyle, autoFocus, ready = true, footer, onChange}: InSelectorProps) { const {translate, dateFnsLocale} = useLocalize(); + const {convertToDisplayString} = useCurrencyListActions(); const personalDetails = usePersonalDetails(); const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); const {options, isLoading} = useFilteredOptions({ @@ -84,6 +86,7 @@ function InSelector({value = [], selectionListTextInputStyle, selectionListStyle ...getSelectedOptionData( createOptionFromReport({ dateFnsLocale, + convertToDisplayString, report: {...reportData, reportID: id}, personalDetails, privateIsArchived, @@ -102,7 +105,7 @@ function InSelector({value = [], selectionListTextInputStyle, selectionListStyle const alternateText = getAlternateText( report, {}, - {dateFnsLocale, isReportArchived, personalDetails, policy, reportAttributesDerived, policyTags: reportPolicyTags, conciergeReportID, isTrackIntentUser}, + {dateFnsLocale, convertToDisplayString, isReportArchived, personalDetails, policy, reportAttributesDerived, policyTags: reportPolicyTags, conciergeReportID, isTrackIntentUser}, ); return {...report, alternateText}; }; @@ -119,6 +122,7 @@ function InSelector({value = [], selectionListTextInputStyle, selectionListStyle ? defaultListOptions : getSearchOptions({ dateFnsLocale, + convertToDisplayString, options, draftComments, betas: undefined, @@ -137,6 +141,7 @@ function InSelector({value = [], selectionListTextInputStyle, selectionListStyle const chatOptions = filterAndOrderOptions(defaultOptions, cleanSearchTerm, countryCode, loginList, currentUserEmail, currentUserAccountID, personalDetails, { dateFnsLocale, + convertToDisplayString, selectedOptions, excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, }); diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx index dfa2ab55100e..76526e7f2de0 100644 --- a/src/components/Search/SearchAutocompleteList.tsx +++ b/src/components/Search/SearchAutocompleteList.tsx @@ -8,6 +8,7 @@ import type {Section, SelectionListWithSectionsHandle} from '@components/Selecti import useAutocompleteSuggestions from '@hooks/useAutocompleteSuggestions'; import useBottomSafeSafeAreaPaddingStyle from '@hooks/useBottomSafeSafeAreaPaddingStyle'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebounce from '@hooks/useDebounce'; import useDebouncedAccessibilityAnnouncement from '@hooks/useDebouncedAccessibilityAnnouncement'; @@ -180,6 +181,7 @@ function SearchAutocompleteList({ }: SearchAutocompleteListProps) { const styles = useThemeStyles(); const {translate, localeCompare, formatPhoneNumber, dateFnsLocale} = useLocalize(); + const {convertToDisplayString} = useCurrencyListActions(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const contentContainerStyle = useBottomSafeSafeAreaPaddingStyle({ addOfflineIndicatorBottomSafeAreaPadding: true, @@ -255,6 +257,7 @@ function SearchAutocompleteList({ } return getSearchOptions({ dateFnsLocale, + convertToDisplayString, options: listOptions, draftComments, betas: betas ?? [], @@ -296,6 +299,7 @@ function SearchAutocompleteList({ isTrackIntentUser, translate, dateFnsLocale, + convertToDisplayString, ]); const [isInitialRender, setIsInitialRender] = useState(true); diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index 7c3733131375..7c31ae6b4f50 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -10,6 +10,7 @@ import {isSearchQueryItem} from '@components/Search/SearchList/ListItem/SearchQu import type {SearchQueryString} from '@components/Search/types'; import type {SelectionListWithSectionsHandle} from '@components/SelectionList/SelectionListWithSections/types'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebouncedState from '@hooks/useDebouncedState'; import useFeedKeysWithAssignedCards from '@hooks/useFeedKeysWithAssignedCards'; @@ -80,6 +81,7 @@ type SearchRouterProps = { function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDisplayed, ref}: SearchRouterProps) { const {translate, formatPhoneNumber, dateFnsLocale} = useLocalize(); + const {convertToDisplayString} = useCurrencyListActions(); const styles = useThemeStyles(); const {setShouldResetSearchQuery} = useSearchQueryActions(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); @@ -218,6 +220,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla const option = createOptionFromReport({ dateFnsLocale, + convertToDisplayString, report: contextualReport, personalDetails, privateIsArchived: contextualReportNVP, @@ -299,6 +302,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla reportAttributes, isTrackIntentUser, dateFnsLocale, + convertToDisplayString, ], ); diff --git a/src/hooks/useAutocompleteSuggestions.ts b/src/hooks/useAutocompleteSuggestions.ts index 1042e685d2bb..d5cc8be676c1 100644 --- a/src/hooks/useAutocompleteSuggestions.ts +++ b/src/hooks/useAutocompleteSuggestions.ts @@ -35,7 +35,7 @@ import {isTrackIntentUserSelector} from '@selectors/Onboarding'; import type {FeedKeysWithAssignedCards} from './useFeedKeysWithAssignedCards'; -import {useCurrencyListState} from './useCurrencyList'; +import {useCurrencyListActions, useCurrencyListState} from './useCurrencyList'; import useExportedToFilterOptions from './useExportedToFilterOptions'; import useLoadSearchCategoryData from './useLoadSearchCategoryData'; import useLocalize from './useLocalize'; @@ -120,6 +120,7 @@ function useAutocompleteSuggestions({ autocompleteSubstitutions, }: UseAutocompleteSuggestionsParams): AutocompleteItemData[] { const {localeCompare, dateFnsLocale} = useLocalize(); + const {convertToDisplayString} = useCurrencyListActions(); const [allPolicyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES); const [allRecentCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES); const [recentCurrencyAutocompleteList] = useOnyx(ONYXKEYS.RECENTLY_USED_CURRENCIES); @@ -247,6 +248,7 @@ function useAutocompleteSuggestions({ const participants = getSearchOptions({ dateFnsLocale, + convertToDisplayString, options, draftComments, betas: betas ?? [], @@ -288,6 +290,7 @@ function useAutocompleteSuggestions({ const filteredReports = getSearchOptions({ dateFnsLocale, + convertToDisplayString, options, draftComments, betas: betas ?? [], diff --git a/src/hooks/useFilteredOptions.ts b/src/hooks/useFilteredOptions.ts index e924ac2887ab..a7d37a307fac 100644 --- a/src/hooks/useFilteredOptions.ts +++ b/src/hooks/useFilteredOptions.ts @@ -6,6 +6,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import {isTrackIntentUserSelector} from '@selectors/Onboarding'; import {useCallback, useMemo, useState} from 'react'; +import {useCurrencyListActions} from './useCurrencyList'; import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails'; import useLocalize from './useLocalize'; import useOnyx from './useOnyx'; @@ -90,6 +91,7 @@ function useFilteredOptions(config: UseFilteredOptionsConfig): UseFilteredOption // Option building is locale-dependent, so a consumer that stays mounted through a language switch recomputes. const {preferredLocale, dateFnsLocale} = useLocalize(); + const {convertToDisplayString} = useCurrencyListActions(); // Sorted report actions from the RAM_ONLY_SORTED_REPORT_ACTIONS derived value; a new reference on // every recompute, so it doubles as the report-actions invalidation signal for the option-list cache. @@ -110,7 +112,17 @@ function useFilteredOptions(config: UseFilteredOptionsConfig): UseFilteredOption reportAttributesDerived, privateIsArchivedMap, allPolicies, - {currentUserAccountID, dateFnsLocale, conciergeReportID, maxRecentReports: reportsLimit, includeP2P, isSearching, deferContactsUntilSearch, locale: preferredLocale}, + { + currentUserAccountID, + dateFnsLocale, + convertToDisplayString, + conciergeReportID, + maxRecentReports: reportsLimit, + includeP2P, + isSearching, + deferContactsUntilSearch, + locale: preferredLocale, + }, undefined, undefined, isTrackIntentUser, @@ -134,6 +146,7 @@ function useFilteredOptions(config: UseFilteredOptionsConfig): UseFilteredOption sortedActions, currentUserAccountID, dateFnsLocale, + convertToDisplayString, ], ); diff --git a/src/hooks/useMoneyRequestParticipantsPolicyTags.ts b/src/hooks/useMoneyRequestParticipantsPolicyTags.ts index 4e238003816a..fc0027a7b8cd 100644 --- a/src/hooks/useMoneyRequestParticipantsPolicyTags.ts +++ b/src/hooks/useMoneyRequestParticipantsPolicyTags.ts @@ -15,6 +15,7 @@ import type {Participant} from '@src/types/onyx/IOU'; import type {Locale as DateFnsLocale} from 'date-fns'; import type {OnyxEntry} from 'react-native-onyx'; +import {useCurrencyListActions} from './useCurrencyList'; import useParticipantsPolicyTags from './useParticipantsPolicyTags'; type UseMoneyRequestParticipantsPolicyTagsParams = { @@ -47,18 +48,20 @@ function useMoneyRequestParticipantsPolicyTags({ translate, dateFnsLocale, }: UseMoneyRequestParticipantsPolicyTagsParams): UseMoneyRequestParticipantsPolicyTagsResult { - const participants = getMoneyRequestParticipantOptions( + const {convertToDisplayString} = useCurrencyListActions(); + const participants = getMoneyRequestParticipantOptions({ currentUserAccountID, report, policy, personalDetails, conciergeReportID, - isArchived, + privateIsArchived: isArchived, reportAttributesDerived, reportDraft, translate, + convertToDisplayString, dateFnsLocale, - ); + }); const participantsPolicyTags = useParticipantsPolicyTags(participants); return {participants, participantsPolicyTags}; diff --git a/src/hooks/useSearchSelector/base.ts b/src/hooks/useSearchSelector/base.ts index bb05387b6220..c1ee92cafa9d 100644 --- a/src/hooks/useSearchSelector/base.ts +++ b/src/hooks/useSearchSelector/base.ts @@ -1,5 +1,6 @@ import {usePersonalDetails} from '@components/OnyxListItemProvider'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebounce from '@hooks/useDebounce'; import useDebouncedState from '@hooks/useDebouncedState'; @@ -195,6 +196,7 @@ function useSearchSelectorBase({ shouldSeparateNonExistingSelectedOptions = false, }: UseSearchSelectorConfig): UseSearchSelectorReturn { const {translate, dateFnsLocale} = useLocalize(); + const {convertToDisplayString} = useCurrencyListActions(); const [betas] = useOnyx(ONYXKEYS.BETAS); const [reportAttributesDerived] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES); const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); @@ -290,6 +292,7 @@ function useSearchSelectorBase({ options: optionsWithContacts, draftComments, dateFnsLocale, + convertToDisplayString, betas: betas ?? [], isUsedInChatFinder: true, includeReadOnly: true, @@ -319,6 +322,7 @@ function useSearchSelectorBase({ conciergeReportID, { dateFnsLocale, + convertToDisplayString, betas: betas ?? [], searchString: computedSearchTerm, searchInputValue: trimmedSearchInput, @@ -354,6 +358,7 @@ function useSearchSelectorBase({ conciergeReportID, { dateFnsLocale, + convertToDisplayString, betas, selectedOptions, includeMultipleParticipantReports: true, @@ -391,6 +396,7 @@ function useSearchSelectorBase({ conciergeReportID, { dateFnsLocale, + convertToDisplayString, betas: betas ?? [], includeP2P: true, includeSelectedOptions: false, diff --git a/src/libs/CurrencyUtils.ts b/src/libs/CurrencyUtils.ts index e1aed9d419c7..fbf346948338 100644 --- a/src/libs/CurrencyUtils.ts +++ b/src/libs/CurrencyUtils.ts @@ -95,13 +95,6 @@ function getLocalizedCurrencySymbol(locale: Locale | undefined, currencyCode: st return parts.find((part) => part.type === 'currency')?.value; } -/** - * Get the currency symbol for a currency(ISO 4217) Code - */ -function getCurrencySymbol(currencyCode: string, currencies?: CurrencyList): string | undefined { - return getCurrencyList(currencies)?.[currencyCode]?.symbol; -} - /** * Takes an amount as a floating point number and converts it to an integer equivalent to the amount in "cents". * This is because the backend always stores amounts in "cents". The backend works in integer cents to avoid precision errors @@ -132,43 +125,6 @@ function convertToFrontendAmountAsString(amountAsInt: number | null | undefined, return (Math.trunc(amountAsInt) / 100.0).toFixed(decimals); } -/** - * Given an amount in the "cents", convert it to a string for display in the UI. - * The backend always handle things in "cents" (subunit equal to 1/100) - * - * @param amountInCents – should be an integer. Anything after a decimal place will be dropped. - * @param currency - IOU currency - */ -function convertToDisplayString(amountInCents = 0, currency: string = CONST.CURRENCY.USD, shouldUseLocalCurrencySymbol = false, currencies?: CurrencyList): string { - const currencyWithFallback = sanitizeCurrencyCode(currency); - const decimals = getCurrencyDecimals(currencyWithFallback, currencies); - const convertedAmount = convertToFrontendAmountAsInteger(amountInCents, decimals); - - if (shouldUseLocalCurrencySymbol) { - const currencySymbol = getCurrencySymbol(currencyWithFallback, currencies); - - if (currencySymbol) { - const formattedNumber = format(IntlStore.getCurrentLocale(), convertedAmount, { - style: 'decimal', - minimumFractionDigits: decimals, - maximumFractionDigits: 2, - }); - return `${currencySymbol}${formattedNumber}`; - } - } - - return format(IntlStore.getCurrentLocale(), convertedAmount, { - style: 'currency', - currency: currencyWithFallback, - - // 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, - }); -} - /** * Same as convertToDisplayString but always formats with the `en` locale. Used for building optimistic * report action messages, which are stored on the action in English regardless of the viewer's locale. @@ -221,14 +177,6 @@ function convertToDisplayStringWithoutCurrencyEnLocale( .join(''); } -/** Same intended use as convertToDisplayString, but purposely omit currency symbol if not provided */ -function convertToDisplayStringWithExplicitCurrency(amountInCents: number, currency: string | undefined, currencies?: CurrencyList): string { - if (!currency) { - return convertToDisplayStringWithoutCurrency(amountInCents, undefined, currencies); - } - return convertToDisplayString(amountInCents, currency, false, currencies); -} - /** * Given the amount in the "cents", convert it to a short string (no decimals) for display in the UI. * The backend always handle things in "cents" (subunit equal to 1/100) @@ -266,44 +214,17 @@ function convertAmountToDisplayString(amount = 0, currency: string = CONST.CURRE }); } -/** - * Acts the same as `convertAmountToDisplayString` but the result string does not contain currency - */ -function convertToDisplayStringWithoutCurrency(amountInCents: number, currency: string = CONST.CURRENCY.USD, currencies?: CurrencyList) { - const sanitizedCurrency = sanitizeCurrencyCode(currency); - const decimals = getCurrencyDecimals(sanitizedCurrency, currencies); - const convertedAmount = convertToFrontendAmountAsInteger(amountInCents, decimals); - return formatToParts(IntlStore.getCurrentLocale(), convertedAmount, { - style: 'currency', - currency: sanitizedCurrency, - - // 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, - }) - .filter((x) => x.type !== 'currency') - .filter((x) => x.type !== 'literal' || x.value.trim().length !== 0) - .map((x) => x.value) - .join(''); -} - export { isValidCurrencyCode, sanitizeCurrencyCode, resetInvalidCurrencyWarningsForTesting, getCurrencyDecimals, - getCurrencySymbol, getLocalizedCurrencySymbol, convertToBackendAmount, convertToFrontendAmountAsInteger, convertToFrontendAmountAsString, - convertToDisplayString, convertToDisplayStringEnLocale, convertAmountToDisplayString, - convertToDisplayStringWithoutCurrency, convertToDisplayStringWithoutCurrencyEnLocale, - convertToDisplayStringWithExplicitCurrency, convertToShortDisplayString, }; diff --git a/src/libs/IOUAmountSubmission.ts b/src/libs/IOUAmountSubmission.ts index 90950979ae4d..912e8183f4f0 100644 --- a/src/libs/IOUAmountSubmission.ts +++ b/src/libs/IOUAmountSubmission.ts @@ -114,6 +114,7 @@ type SubmitAmountArgs = { conciergeReportID: OnyxEntry; getCurrencyDecimals: CurrencyListActionsContextType['getCurrencyDecimals']; getCurrencySymbol: CurrencyListActionsContextType['getCurrencySymbol']; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; conciergeChat: OnyxEntry; }; @@ -247,7 +248,19 @@ function buildSubmitAmountContext(args: SubmitAmountArgs): SubmitAmountContext { } function buildReportParticipants(args: SubmitAmountArgs) { - const {report, policy, currentUserPersonalDetails, reportAttributesDerivedValue, allReportDrafts, allReportNVPs, allPersonalDetails, conciergeReportID, translate, dateFnsLocale} = args; + const { + report, + policy, + currentUserPersonalDetails, + reportAttributesDerivedValue, + allReportDrafts, + allReportNVPs, + allPersonalDetails, + conciergeReportID, + translate, + dateFnsLocale, + convertToDisplayString, + } = args; const selectedParticipants = getMoneyRequestParticipantsFromReport(report, currentUserPersonalDetails.accountID); const reportAttributesReports = reportAttributesDerivedValue?.reports; const reportIDToCheck = isMoneyRequestReport(report) ? report?.chatReportID : report?.reportID; @@ -260,6 +273,7 @@ function buildReportParticipants(args: SubmitAmountArgs) { : getReportOption(participant, privateIsArchived, policy, allPersonalDetails, conciergeReportID, reportAttributesReports, reportDraft, currentUserPersonalDetails.accountID, { translate, dateFnsLocale, + convertToDisplayString, }); }); } diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.ts b/src/libs/Notification/LocalNotification/BrowserNotifications.ts index 03edc036cfdb..5ea232a0d2af 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.ts +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.ts @@ -1,27 +1,60 @@ import EXPENSIFY_ICON_URL from '@assets/images/expensify-logo-round-clearspace.png'; +import type {CurrencyListActionsContextType} from '@components/CurrencyListContextProvider/types'; + import * as AppUpdate from '@libs/actions/AppUpdate'; -import {convertToDisplayString} from '@libs/CurrencyUtils'; +import {convertToFrontendAmountAsInteger, sanitizeCurrencyCode} from '@libs/CurrencyUtils'; import {translateLocal} from '@libs/Localize'; import Log from '@libs/Log'; import {getForReportAction} from '@libs/ModifiedExpenseMessage'; import NotificationPermission from '@libs/Notification/notificationPermission'; +import {format} from '@libs/NumberFormatUtils'; import {getTextFromHtml} from '@libs/ReportActionsUtils'; import {deprecatedGetReportName} from '@libs/ReportNameUtils'; import * as ReportUtils from '@libs/ReportUtils'; import playSound, {SOUNDS} from '@libs/Sound'; -import type {Report, ReportAction, ReportAttributesDerivedValue} from '@src/types/onyx'; +import CONST from '@src/CONST'; +import IntlStore from '@src/languages/IntlStore'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {CurrencyList, Report, ReportAction, ReportAttributesDerivedValue} from '@src/types/onyx'; import type {ImageSourcePropType} from 'react-native'; // Web implementation only. Do not import for direct use. Use LocalNotification. import {SafeString, Str} from 'expensify-common'; +import Onyx from 'react-native-onyx'; import type {LocalNotificationClickHandler, LocalNotificationData, LocalNotificationModifiedExpensePushParams} from './types'; const notificationCache: Record = {}; +// The browser-notification pipeline is driven by Pusher events outside React, so there is no component to inject the +// currency formatter from CurrencyListContextProvider. Subscribe to the currency list here and mirror the provider's +// implementation instead of relying on CurrencyUtils' module-scope fallback. +let currencyList: CurrencyList = {}; +Onyx.connectWithoutView({ + key: ONYXKEYS.CURRENCY_LIST, + callback: (value) => { + currencyList = value ?? {}; + }, +}); +const convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString'] = (amountInCents, currencyCode) => { + const sanitizedCurrency = sanitizeCurrencyCode(currencyCode); + const decimals = currencyList?.[sanitizedCurrency]?.decimals ?? CONST.DEFAULT_CURRENCY_DECIMALS; + const convertedAmount = convertToFrontendAmountAsInteger(amountInCents ?? 0, decimals); + return format(IntlStore.getCurrentLocale(), convertedAmount, { + style: 'currency', + currency: sanitizedCurrency, + + // 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, + }); +}; + /** * Checks if the user has granted permission to show browser notifications, prompting them * if they have not yet decided. @@ -165,7 +198,6 @@ export default { const title = reportAction.person?.map((f) => f.text).join(', ') ?? ''; const bodyWithHTML = getForReportAction({ translate: translateLocal, - // Non-React call path (pusher/notification pipeline): pass the standalone util, which falls back to the module-scope currency list. convertToDisplayString, reportAction, policy, diff --git a/src/libs/OptionsListUtils/index.ts b/src/libs/OptionsListUtils/index.ts index 9f42fee2d6d5..d8cbcdf7fa11 100644 --- a/src/libs/OptionsListUtils/index.ts +++ b/src/libs/OptionsListUtils/index.ts @@ -2,6 +2,7 @@ import FallbackAvatar from '@assets/images/avatars/fallback-avatar.svg'; import type {LocaleContextProps, LocalizedTranslate} from '@components/LocaleContextProvider'; +import type {CurrencyListActionsContextType} from '@hooks/useCurrencyList'; import type {PrivateIsArchivedMap} from '@hooks/usePrivateIsArchivedMap'; import {getEnabledCategoriesCount} from '@libs/CategoryUtils'; @@ -242,6 +243,7 @@ type GetAlternateTextConfig = { // TODO: Remove optional (?) once all callers pass sortedActions. Refactor issue: https://github.com/Expensify/App/issues/66381 sortedActions?: Record; isTrackIntentUser?: boolean; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; // TODO: Remove optional (?) once all callers pass currentUserAccountID. Refactor issue: https://github.com/Expensify/App/issues/66408 currentUserAccountID?: number; }; @@ -259,6 +261,7 @@ function getAlternateText( lastActorDetails = {}, visibleReportActionsData = {}, translate, + convertToDisplayString, dateFnsLocale, reportAttributesDerived, policyTags, @@ -281,6 +284,7 @@ function getAlternateText( formatReportLastMessageText(isLastActionAddComment ? (option.lastMessageText ?? '') : Parser.htmlToText(option.lastMessageText ?? '')) || getLastMessageTextForReport({ translate: translateFn, + convertToDisplayString, dateFnsLocale, report, personalDetails, @@ -370,6 +374,7 @@ type CreateOptionParams = { policyTags?: OnyxEntry; visibleReportActionsData?: VisibleReportActionsDerivedValue; translate?: LocalizedTranslate; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; isTrackIntentUser?: boolean; conciergeReportID: string | undefined; // TODO: Remove optional (?) once all callers pass sortedActions. Refactor issue: https://github.com/Expensify/App/issues/66381 @@ -412,6 +417,7 @@ function createOption({ policyTags, visibleReportActionsData = {}, translate, + convertToDisplayString, dateFnsLocale, isTrackIntentUser, conciergeReportID, @@ -492,6 +498,7 @@ function createOption({ const lastActorDetails = personalDetails?.[report?.lastActorAccountID ?? String(CONST.DEFAULT_NUMBER_ID)] ?? {}; result.lastMessageText = getLastMessageTextForReport({ translate: translateFn, + convertToDisplayString, dateFnsLocale, report, personalDetails, @@ -520,6 +527,7 @@ function createOption({ lastActorDetails, visibleReportActionsData, translate: translateFn, + convertToDisplayString, reportAttributesDerived, policyTags, conciergeReportID, @@ -587,16 +595,17 @@ function getReportOption( reportAttributesDerived: ReportAttributesDerivedValue['reports'] | undefined, reportDraft: OnyxEntry, currentUserAccountID: number, - localize: {translate: LocalizedTranslate; dateFnsLocale: DateFnsLocale | undefined}, + localize: {translate: LocalizedTranslate; dateFnsLocale: DateFnsLocale | undefined; convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']}, policyTags?: OnyxCollection, ): OptionData { - const {translate, dateFnsLocale} = localize; + const {translate, dateFnsLocale, convertToDisplayString} = localize; const report = getReportOrDraftReport(participant.reportID, undefined, undefined, reportDraft); const visibleParticipantAccountIDs = getParticipantsAccountIDsForDisplay(report, true); const reportPolicyTags = policyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${getNonEmptyStringOnyxID(report?.policyID)}`]; const option = createOption({ dateFnsLocale, + convertToDisplayString, accountIDs: visibleParticipantAccountIDs, personalDetails: personalDetails ?? {}, report: !isEmptyObject(report) ? report : undefined, @@ -653,6 +662,7 @@ type GetReportDisplayOptionParams = { reportAttributesDerived?: ReportAttributesDerivedValue['reports']; policyTags?: OnyxEntry; visibleReportActionsData?: VisibleReportActionsDerivedValue; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; }; /** @@ -666,6 +676,7 @@ function getReportDisplayOption({ policy, conciergeReportID, translate, + convertToDisplayString, dateFnsLocale, currentUserAccountID, reportAttributesDerived, @@ -676,6 +687,7 @@ function getReportDisplayOption({ const option = createOption({ dateFnsLocale, + convertToDisplayString, accountIDs: visibleParticipantAccountIDs, personalDetails: personalDetails ?? {}, report: !isEmptyObject(report) ? report : undefined, @@ -721,19 +733,20 @@ function getPolicyExpenseReportOption( personalDetails: OnyxEntry, expenseReport: OnyxEntry, policy: OnyxEntry, - localize: {translate: LocalizedTranslate; dateFnsLocale: DateFnsLocale | undefined}, + localize: {translate: LocalizedTranslate; dateFnsLocale: DateFnsLocale | undefined; convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']}, currentUserAccountID: number, reportAttributesDerived?: ReportAttributesDerivedValue['reports'], policyTags?: OnyxEntry, visibleReportActionsData: VisibleReportActionsDerivedValue = {}, ): SearchOptionData { - const {translate, dateFnsLocale} = localize; + const {translate, dateFnsLocale, convertToDisplayString} = localize; const visibleParticipantAccountIDs = Object.entries(expenseReport?.participants ?? {}) .filter(([, reportParticipant]) => reportParticipant && !isHiddenForCurrentUser(reportParticipant.notificationPreference)) .map(([accountID]) => Number(accountID)); const option = createOption({ dateFnsLocale, + convertToDisplayString, accountIDs: visibleParticipantAccountIDs, personalDetails: personalDetails ?? {}, report: !isEmptyObject(expenseReport) ? expenseReport : null, @@ -868,8 +881,10 @@ function processReport( isTrackIntentUser, sortedActions, currentUserAccountID, + convertToDisplayString, }: { currentUserAccountID: number; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; reportAttributesDerived?: ReportAttributesDerivedValue['reports']; policyTags?: OnyxEntry; visibleReportActionsData?: VisibleReportActionsDerivedValue; @@ -902,6 +917,7 @@ function processReport( item: report, ...createOption({ dateFnsLocale, + convertToDisplayString, accountIDs, personalDetails, report, @@ -995,6 +1011,7 @@ function buildFullOption(accountID: number, item: PersonalDetails | null, report currentUserAccountID, dateFnsLocale, translate, + convertToDisplayString, } = context; const privateIsArchived = report ? privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`] : undefined; const policy = policiesCollection?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`]; @@ -1004,6 +1021,7 @@ function buildFullOption(accountID: number, item: PersonalDetails | null, report item, ...createOption({ dateFnsLocale, + convertToDisplayString, accountIDs: [accountID], personalDetails, report, @@ -1082,6 +1100,7 @@ function createFilteredOptionList( options: { currentUserAccountID: number; dateFnsLocale: DateFnsLocale | undefined; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; conciergeReportID: string | undefined; maxRecentReports?: number; /** Whether to build contact shells. */ @@ -1132,6 +1151,9 @@ function createFilteredOptionList( // date-fns locale are part of the output. activeLocale, options.dateFnsLocale, + // Money-request previews format amounts with this function; the provider memoizes it on the + // currency list and locale, so a new reference signals the formatting inputs changed. + options.convertToDisplayString, // The RAM_ONLY_SORTED_REPORT_ACTIONS derived value produces a new object on every recompute, // so its reference signals that the underlying report actions changed. sortedActions, @@ -1190,6 +1212,7 @@ function createFilteredOptionList( const policy = policiesCollection?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`]; const reportPolicyTags = policyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${getNonEmptyStringOnyxID(report?.policyID)}`]; const {reportMapEntry, reportOption} = processReport(report, personalDetails, privateIsArchived, policy, conciergeReportID, options.dateFnsLocale, { + convertToDisplayString: options.convertToDisplayString, reportAttributesDerived, policyTags: reportPolicyTags, visibleReportActionsData, @@ -1230,6 +1253,7 @@ function createFilteredOptionList( conciergeReportID, currentUserAccountID, dateFnsLocale: options.dateFnsLocale, + convertToDisplayString: options.convertToDisplayString, translate: translateInActiveLocale, }) : []; @@ -1273,6 +1297,7 @@ type CreateOptionFromReportParams = { policyTags?: OnyxEntry; visibleReportActionsData?: VisibleReportActionsDerivedValue; isTrackIntentUser?: boolean; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; }; function createOptionFromReport({ @@ -1288,6 +1313,7 @@ function createOptionFromReport({ policyTags, visibleReportActionsData = {}, isTrackIntentUser, + convertToDisplayString, }: CreateOptionFromReportParams) { const accountIDs = getParticipantsAccountIDsForDisplay(report); @@ -1295,6 +1321,7 @@ function createOptionFromReport({ item: report, ...createOption({ dateFnsLocale, + convertToDisplayString, accountIDs, personalDetails, report, @@ -1612,6 +1639,7 @@ function canCreateOptimisticPersonalDetailOption({ */ function getUserToInviteOption({ dateFnsLocale, + convertToDisplayString, searchValue, personalDetails, searchInputValue, @@ -1657,6 +1685,7 @@ function getUserToInviteOption({ }; const userToInvite = createOption({ dateFnsLocale, + convertToDisplayString, accountIDs: [optimisticAccountID], personalDetails: personalDetailsExtended, report: null, @@ -1858,7 +1887,12 @@ function prepareReportOptionsForDisplay( options: Array>, policiesCollection: OnyxCollection, isOffline: boolean, - config: GetValidReportsConfig & {translate: LocalizedTranslate; dateFnsLocale: DateFnsLocale | undefined; currentUserAccountID?: number}, + config: GetValidReportsConfig & { + translate: LocalizedTranslate; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; + dateFnsLocale: DateFnsLocale | undefined; + currentUserAccountID?: number; + }, conciergeReportID: string | undefined, sortedActions: Record | undefined, visibleReportActionsData: VisibleReportActionsDerivedValue = {}, @@ -1880,6 +1914,7 @@ function prepareReportOptionsForDisplay( shouldUnreadBeBold = false, personalDetails, translate, + convertToDisplayString, currentUserAccountID, } = config; @@ -1911,6 +1946,8 @@ function prepareReportOptionsForDisplay( policy, lastActorDetails, visibleReportActionsData, + translate, + convertToDisplayString, reportAttributesDerived, policyTags: reportPolicyTags, conciergeReportID, @@ -2344,6 +2381,7 @@ function getValidOptions( countryCode, { dateFnsLocale, + convertToDisplayString: config.convertToDisplayString, excludeLogins: loginsToExclude, shouldAcceptName, searchInputValue, @@ -2366,6 +2404,7 @@ function getValidOptions( type SearchOptionsConfig = { dateFnsLocale: DateFnsLocale | undefined; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; options: OptionList; draftComments: OnyxCollection; betas?: Beta[]; @@ -2425,6 +2464,7 @@ function getSearchOptions({ excludeFromSuggestionsOnly = {}, isTrackIntentUser, translate, + convertToDisplayString, }: SearchOptionsConfig): OptionsResult { const optionList = getValidOptions( options, @@ -2436,6 +2476,7 @@ function getSearchOptions({ conciergeReportID, { dateFnsLocale, + convertToDisplayString, betas, includeRecentReports, includeMultipleParticipantReports: true, @@ -2597,6 +2638,7 @@ function formatSectionsFromSearchTerm( currentUserAccountID: number, allPolicies: OnyxCollection, translate: LocalizedTranslate, + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString'], dateFnsLocale: DateFnsLocale | undefined, personalDetails: OnyxEntry = {}, shouldGetOptionDetails = false, @@ -2627,7 +2669,7 @@ function formatSectionsFromSearchTerm( personalDetails, expenseReport, expenseReportPolicy, - {translate, dateFnsLocale}, + {translate, dateFnsLocale, convertToDisplayString}, currentUserAccountID, reportAttributesDerived, ); @@ -2668,7 +2710,7 @@ function formatSectionsFromSearchTerm( personalDetails, expenseReport, expenseReportPolicy, - {translate, dateFnsLocale}, + {translate, dateFnsLocale, convertToDisplayString}, currentUserAccountID, reportAttributesDerived, ); @@ -2774,10 +2816,10 @@ function filterUserToInvite( loginList: OnyxEntry, currentUserEmail: string, personalDetails: OnyxEntry, - countryCode: number = CONST.DEFAULT_COUNTRY_CODE, - config?: FilterUserToInviteConfig, + countryCode: number, + config: FilterUserToInviteConfig, ): SearchOptionData | null { - const {canInviteUser = true, excludeLogins = {}, dateFnsLocale} = config ?? {}; + const {canInviteUser = true, excludeLogins = {}} = config; if (!canInviteUser) { return null; } @@ -2798,7 +2840,6 @@ function filterUserToInvite( ...excludeLogins, }; return getUserToInviteOption({ - dateFnsLocale, searchValue, personalDetails, loginsToExclude, @@ -2821,7 +2862,7 @@ function filterOptions( currentUserEmail: string, currentUserAccountID: number, personalDetailsCollection: OnyxEntry, - config?: FilterUserToInviteConfig, + config: FilterUserToInviteConfig, ): Options { const trimmedSearchInput = searchInputValue.trim(); const searchInputValueForInvite = config?.searchInputValue ?? trimmedSearchInput; @@ -2846,8 +2887,6 @@ function filterOptions( countryCode, { ...config, - // `config` is optional, so the required locale has to be set explicitly rather than relying on the spread. - dateFnsLocale: config?.dateFnsLocale, searchInputValue: searchInputValueForInvite, }, ); @@ -2911,7 +2950,7 @@ function filterAndOrderOptions( currentUserEmail: string, currentUserAccountID: number, personalDetails: OnyxEntry, - config?: FilterAndOrderConfig, + config: FilterAndOrderConfig, ): Options { let filterResult = options; if (searchInputValue.trim().length > 0) { diff --git a/src/libs/OptionsListUtils/types.ts b/src/libs/OptionsListUtils/types.ts index bb3a6d6f6702..92f93cc52ff2 100644 --- a/src/libs/OptionsListUtils/types.ts +++ b/src/libs/OptionsListUtils/types.ts @@ -1,6 +1,7 @@ import type {LocalizedTranslate} from '@components/LocaleContextProvider'; import type {Section as SelectionListSection} from '@components/SelectionList/SelectionListWithSections/types'; +import type {CurrencyListActionsContextType} from '@hooks/useCurrencyList'; import type {PrivateIsArchivedMap} from '@hooks/usePrivateIsArchivedMap'; import type {OptionData} from '@libs/ReportUtils'; @@ -118,6 +119,9 @@ type LazyHydrationContext = { /** Locale used when the option list was built. */ translate: LocalizedTranslate; + + /** Currency formatter used when the option list was built. */ + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; }; type SearchOption = SearchOptionData & { @@ -264,6 +268,7 @@ type IsValidReportsConfig = Pick< type GetOptionsConfig = { dateFnsLocale: DateFnsLocale | undefined; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; excludeLogins?: Record; excludeFromSuggestionsOnly?: Record; includeCurrentUser?: boolean; @@ -303,6 +308,7 @@ type GetUserToInviteConfig = { countryCode?: number; loginList: OnyxEntry; currentUserEmail: string; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; } & Pick; type MemberForList = { @@ -345,6 +351,7 @@ type PreviewConfig = { type FilterUserToInviteConfig = Pick & { dateFnsLocale: DateFnsLocale | undefined; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; canInviteUser?: boolean; excludeLogins?: Record; }; diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 2fc80d26e4ac..771ea1c3db96 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -57,7 +57,7 @@ import type {OptimisticIOUReportAction, PartialReportAction} from './ReportUtils import {getBankName, isCardPendingActivate} from './CardUtils'; import {getDecodedCategoryName} from './CategoryUtils'; -import {convertAmountToDisplayString, convertToBackendAmount, convertToDisplayStringWithExplicitCurrency, convertToShortDisplayString} from './CurrencyUtils'; +import {convertAmountToDisplayString, convertToBackendAmount, convertToShortDisplayString} from './CurrencyUtils'; import DateUtils from './DateUtils'; import {getFormattedDistanceInUnits} from './DistanceDisplayUtils'; import {getEnvironmentURL, getOldDotEnvironmentURL} from './Environment/Environment'; @@ -4787,13 +4787,19 @@ function getRoomChangeLogMessage(translate: LocalizedTranslate, reportAction: Re function getActionableCard3DSTransactionApprovalMessage( translate: LocalizedTranslate, reportAction: ReportAction, + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString'], + convertToDisplayStringWithoutCurrency: CurrencyListActionsContextType['convertToDisplayStringWithoutCurrency'], ) { const originalMessage = getOriginalMessage(reportAction); if (!originalMessage) { return undefined; } const {amount, currency, merchant} = originalMessage; - const formattedAmount = amount ? convertToDisplayStringWithExplicitCurrency(amount, currency) : ''; + let formattedAmount = ''; + if (amount) { + // Show the amount without any currency symbol when the message carries no currency, rather than defaulting to USD. + formattedAmount = currency ? convertToDisplayString(amount, currency) : convertToDisplayStringWithoutCurrency(amount); + } return translate('report.actions.type.actionableCard3DSTransactionApproval', formattedAmount, merchant); } diff --git a/src/libs/ReportAlternateTextUtils.ts b/src/libs/ReportAlternateTextUtils.ts index b6819f89a522..b25f70d4fcae 100644 --- a/src/libs/ReportAlternateTextUtils.ts +++ b/src/libs/ReportAlternateTextUtils.ts @@ -27,7 +27,6 @@ import {Str} from 'expensify-common'; import Onyx from 'react-native-onyx'; import {getAddAgentRuleMessage, getDeleteAgentRuleMessage, getUpdateAgentRuleMessage} from './AgentRuleChangeLogUtils'; -import {convertToDisplayString as convertToDisplayStringUtil} from './CurrencyUtils'; import {isReportMessageAttachment} from './isReportMessageAttachment'; import {formatPhoneNumber as formatPhoneNumberPhoneUtils} from './LocalePhoneNumber'; import {formatList} from './Localize'; @@ -438,6 +437,7 @@ function getLastActorDisplayNameFromLastVisibleActions( */ function getLastMessageTextForReport({ translate, + convertToDisplayString, dateFnsLocale, report, personalDetails, @@ -458,6 +458,7 @@ function getLastMessageTextForReport({ currentUserAccountID, }: { translate: LocalizedTranslate; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; dateFnsLocale: DateFnsLocale | undefined; report: OnyxEntry; personalDetails: OnyxEntry; @@ -542,8 +543,7 @@ function getLastMessageTextForReport({ } } } else if (isMoneyRequestAction(lastReportAction)) { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. - const properSchemaForMoneyRequestMessage = getReportPreviewMessage(translate, convertToDisplayStringUtil, { + const properSchemaForMoneyRequestMessage = getReportPreviewMessage(translate, convertToDisplayString, { reportOrID: report, iouReportAction: lastReportAction, shouldConsiderScanningReceiptOrPendingRoute: true, @@ -566,8 +566,7 @@ function getLastMessageTextForReport({ const reportName = reportAttributesDerived?.[iouReport.reportID]?.reportName ?? ''; lastMessageTextFromReport = formatReportLastMessageText(reportName); } else { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. - const reportPreviewMessage = getReportPreviewMessage(translate, convertToDisplayStringUtil, { + const reportPreviewMessage = getReportPreviewMessage(translate, convertToDisplayString, { reportOrID: !isEmptyObject(iouReport) ? iouReport : null, iouReportAction: lastIOUMoneyReportAction ?? lastReportAction, shouldConsiderScanningReceiptOrPendingRoute: true, @@ -584,8 +583,7 @@ function getLastMessageTextForReport({ } else if (isReimbursementQueuedAction(lastReportAction)) { lastMessageTextFromReport = getReimbursementQueuedActionMessage({reportAction: lastReportAction, translate, formatPhoneNumber: formatPhoneNumberPhoneUtils, report}); } else if (isReimbursementDeQueuedOrCanceledAction(lastReportAction)) { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. - lastMessageTextFromReport = getReimbursementDeQueuedOrCanceledActionMessage(translate, lastReportAction, report?.ownerAccountID, convertToDisplayStringUtil); + lastMessageTextFromReport = getReimbursementDeQueuedOrCanceledActionMessage(translate, lastReportAction, report?.ownerAccountID, convertToDisplayString); } else if (isDeletedParentAction(lastReportAction) && reportUtilsIsChatReport(report)) { lastMessageTextFromReport = getDeletedParentActionMessageForChatReport(lastReportAction); } else if (isPendingRemove(lastReportAction) && report?.reportID && isThreadParentMessage(lastReportAction, report.reportID)) { @@ -600,8 +598,7 @@ function getLastMessageTextForReport({ report?.ownerAccountID, getLoginByAccountID(report?.ownerAccountID, personalDetails), getLoginByAccountID(lastReportAction.actorAccountID, personalDetails), - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. - convertToDisplayStringUtil, + convertToDisplayString, currentUserAccountID, ); } else if (isReportMessageAttachment({text: report?.lastMessageText ?? '', html: report?.lastMessageHtml, type: ''})) { @@ -609,8 +606,7 @@ function getLastMessageTextForReport({ } else if (isModifiedExpenseAction(lastReportAction)) { const properSchemaForModifiedExpenseMessageWithHTML = getForReportAction({ translate, - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. - convertToDisplayString: convertToDisplayStringUtil, + convertToDisplayString, reportAction: lastReportAction, policy, movedFromReport, @@ -732,8 +728,7 @@ function getLastMessageTextForReport({ } else if (isRenamedAction(lastReportAction)) { lastMessageTextFromReport = getRenamedAction(translate, lastReportAction, isExpenseReport(report)); } else if (isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.DELETED_TRANSACTION)) { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. - lastMessageTextFromReport = getDeletedTransactionMessage(translate, lastReportAction, convertToDisplayStringUtil); + lastMessageTextFromReport = getDeletedTransactionMessage(translate, lastReportAction, convertToDisplayString); } else if ( isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.TAKE_CONTROL) || isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.REROUTE) || @@ -758,8 +753,7 @@ function getLastMessageTextForReport({ lastMessageTextFromReport = getDynamicExternalWorkflowRoutedMessage(lastReportAction, translate); } if (isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_MAX_EXPENSE_AMOUNT)) { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. - lastMessageTextFromReport = getPolicyChangeLogMaxExpenseAmountMessage(translate, lastReportAction, convertToDisplayStringUtil); + lastMessageTextFromReport = getPolicyChangeLogMaxExpenseAmountMessage(translate, lastReportAction, convertToDisplayString); } if (isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_MAX_EXPENSE_AGE)) { lastMessageTextFromReport = getPolicyChangeLogMaxExpenseAgeMessage(translate, lastReportAction); @@ -792,8 +786,7 @@ function getLastMessageTextForReport({ lastMessageTextFromReport = getUpdatedAutoHarvestingMessage(translate, lastReportAction); } if (isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_AUTO_REIMBURSEMENT)) { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. - lastMessageTextFromReport = getAutoReimbursementMessage(translate, lastReportAction, convertToDisplayStringUtil); + lastMessageTextFromReport = getAutoReimbursementMessage(translate, lastReportAction, convertToDisplayString); } if (isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_CATEGORY_TAX_RATE)) { lastMessageTextFromReport = getCategoryTaxRateMessage(translate, lastReportAction); @@ -889,16 +882,14 @@ function getLastMessageTextForReport({ } else if (report?.transactionCount && report?.transactionCount > 0 && report?.currency) { const latestVisibleMoneyRequestAction = getLatestVisibleMoneyRequestAction(reportID, canUserPerformWrite, sortedActions?.[reportID], visibleReportActionsDataParam); if (isExpenseReport(report) && latestVisibleMoneyRequestAction) { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. - lastMessageTextFromReport = getExpenseReportPreviewText(report, latestVisibleMoneyRequestAction, translate, transactions, convertToDisplayStringUtil); + lastMessageTextFromReport = getExpenseReportPreviewText(report, latestVisibleMoneyRequestAction, translate, transactions, convertToDisplayString); } else if (!isExpenseReport(report)) { lastMessageTextFromReport = lastVisibleMessage?.lastMessageText; } else if (!isCreatedAction(lastReportAction)) { lastMessageTextFromReport = formatReportLastMessageText( Parser.htmlToText( - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. - getReportPreviewMessage(translate, convertToDisplayStringUtil, { + getReportPreviewMessage(translate, convertToDisplayString, { reportOrID: report, iouReportAction: lastReportAction, shouldConsiderScanningReceiptOrPendingRoute: true, @@ -1114,6 +1105,7 @@ type GetReportAlternateTextParams = { formatPhoneNumber: LocaleContextProps['formatPhoneNumber']; dateFnsLocale: DateFnsLocale | undefined; convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; + convertToDisplayStringWithoutCurrency: CurrencyListActionsContextType['convertToDisplayStringWithoutCurrency']; }; /** @@ -1145,6 +1137,7 @@ function getReportAlternateText({ formatPhoneNumber, dateFnsLocale, convertToDisplayString, + convertToDisplayStringWithoutCurrency, }: GetReportAlternateTextParams): string | undefined { let alternateText: string | undefined; const isChatRoomReport = isChatRoom(report); @@ -1181,6 +1174,7 @@ function getReportAlternateText({ if (!lastMessageTextFromReport) { lastMessageTextFromReport = getLastMessageTextForReport({ translate, + convertToDisplayString, dateFnsLocale, report, personalDetails, @@ -1205,7 +1199,7 @@ function getReportAlternateText({ // Specifically for concierge chats and expense reports, which don't meet any of the conditions in the if statement below if (isActionOfType(lastAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_CARD_3DS_TRANSACTION_APPROVAL)) { - lastMessageText = getActionableCard3DSTransactionApprovalMessage(translate, lastAction) ?? lastMessageText; + lastMessageText = getActionableCard3DSTransactionApprovalMessage(translate, lastAction, convertToDisplayString, convertToDisplayStringWithoutCurrency) ?? lastMessageText; } else if (isActionOfType(lastAction, CONST.REPORT.ACTIONS.TYPE.ACTION_DELEGATE_SUBMIT) && !!getDelegateSubmitMessage(translate, lastAction, currentUserLogin)) { lastMessageText = Parser.htmlToText(getDelegateSubmitMessage(translate, lastAction, currentUserLogin)); } diff --git a/src/libs/ReportNameUtils.ts b/src/libs/ReportNameUtils.ts index adcc0333e2d9..d00bb33ba441 100644 --- a/src/libs/ReportNameUtils.ts +++ b/src/libs/ReportNameUtils.ts @@ -1,5 +1,7 @@ import type {LocaleContextProps, LocalizedTranslate} from '@components/LocaleContextProvider'; +import type {CurrencyListActionsContextType} from '@hooks/useCurrencyList'; + import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type { @@ -26,7 +28,6 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import {Str} from 'expensify-common'; import {getAddAgentRuleMessage, getDeleteAgentRuleMessage, getUpdateAgentRuleMessage} from './AgentRuleChangeLogUtils'; -import {convertToDisplayString, getCurrencySymbol} from './CurrencyUtils'; import {formatPhoneNumber as formatPhoneNumberPhoneUtils} from './LocalePhoneNumber'; import {translateLocal} from './Localize'; // eslint-disable-next-line import/no-cycle @@ -205,6 +206,9 @@ type ComputeReportName = { reportAttributes?: ReportAttributesDerivedValue['reports']; reportTransactions: Record; isTrackIntentUser: boolean | undefined; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; + convertToDisplayStringWithoutCurrency: CurrencyListActionsContextType['convertToDisplayStringWithoutCurrency']; + getCurrencySymbol: CurrencyListActionsContextType['getCurrencySymbol']; pendingDeleteMemberAccountIDs?: string[]; }; @@ -379,6 +383,7 @@ function getInvoiceReportName( report: OnyxEntry, linkedTransactions: Transaction[], translate: LocalizedTranslate, + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString'], personalDetailsList: OnyxEntry, policy?: OnyxEntry, invoiceReceiverPolicy?: OnyxEntry, @@ -390,6 +395,7 @@ function getInvoiceReportName( linkedTransactions, personalDetailsList, translate, + convertToDisplayString, }); const oldDotInvoiceName = report?.reportName ?? moneyRequestReportName; return isNewDotInvoice(report?.chatReportID) ? moneyRequestReportName : oldDotInvoiceName; @@ -426,6 +432,7 @@ function getMoneyRequestReportName({ linkedTransactions, personalDetailsList, translate, + convertToDisplayString, }: { report: OnyxEntry; policy?: OnyxEntry; @@ -433,6 +440,7 @@ function getMoneyRequestReportName({ linkedTransactions: Transaction[]; personalDetailsList: OnyxEntry; translate: LocalizedTranslate; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; }): string { // For expense reports with empty fieldList and empty reportName, return "New Report" (matches OldDot behavior) if (isExpenseReport(report)) { @@ -493,6 +501,8 @@ function computeReportNameBasedOnReportAction({ reportAttributes, isTrackIntentUser, currentUserAccountID, + convertToDisplayString, + convertToDisplayStringWithoutCurrency, }: { translate: LocalizedTranslate; dateFnsLocale: DateFnsLocale | undefined; @@ -505,6 +515,8 @@ function computeReportNameBasedOnReportAction({ reportAttributes: ReportAttributesDerivedValue['reports'] | undefined; isTrackIntentUser: boolean | undefined; currentUserAccountID: number; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; + convertToDisplayStringWithoutCurrency: CurrencyListActionsContextType['convertToDisplayStringWithoutCurrency']; }): string | undefined { if (!parentReportAction) { return undefined; @@ -574,7 +586,6 @@ function computeReportNameBasedOnReportAction({ } if (isReimbursementDeQueuedOrCanceledAction(parentReportAction)) { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. return getReimbursementDeQueuedOrCanceledActionMessage(translate, parentReportAction, parentReport?.ownerAccountID, convertToDisplayString); } if (isRejectedAction(parentReportAction)) { @@ -652,7 +663,6 @@ function computeReportNameBasedOnReportAction({ } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_MAX_EXPENSE_AMOUNT)) { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. return getPolicyChangeLogMaxExpenseAmountMessage(translate, parentReportAction, convertToDisplayString); } @@ -661,12 +671,10 @@ function computeReportNameBasedOnReportAction({ } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_MAX_EXPENSE_AMOUNT_NO_RECEIPT)) { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. return getPolicyChangeLogMaxExpenseAmountNoReceiptMessage(translate, parentReportAction, convertToDisplayString); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_MAX_EXPENSE_AMOUNT_NO_ITEMIZED_RECEIPT)) { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. return getPolicyChangeLogMaxExpenseAmountNoItemizedReceiptMessage(translate, parentReportAction, convertToDisplayString); } @@ -696,7 +704,6 @@ function computeReportNameBasedOnReportAction({ return getAutoPayApprovedReportsEnabledMessage(translate, parentReportAction); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_AUTO_REIMBURSEMENT)) { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. return getAutoReimbursementMessage(translate, parentReportAction, convertToDisplayString); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_CATEGORY_TAX_RATE)) { @@ -753,7 +760,7 @@ function computeReportNameBasedOnReportAction({ } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_CARD_3DS_TRANSACTION_APPROVAL)) { - return getActionableCard3DSTransactionApprovalMessage(translate, parentReportAction); + return getActionableCard3DSTransactionApprovalMessage(translate, parentReportAction, convertToDisplayString, convertToDisplayStringWithoutCurrency); } if (isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.POLICY_CHANGE_LOG.UPDATE_ADDRESS)) { @@ -812,7 +819,6 @@ function computeReportNameBasedOnReportAction({ return getElsewherePaymentReportActionMessage(translate, originalMessage); } if (originalMessage.paymentType === CONST.IOU.PAYMENT_TYPE.VBBA) { - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. const crossBorderMessage = getCrossBorderReimbursedMessage(translate, originalMessage, convertToDisplayString, last4Digits); if (crossBorderMessage) { return crossBorderMessage; @@ -962,17 +968,31 @@ function computeReportNameBasedOnReportAction({ return undefined; } -function computeChatThreadReportName( - translate: LocalizedTranslate, - isArchived: boolean, - report: Report, - reports: OnyxCollection, - currentUserLogin: string, - transactions: OnyxCollection, - parentReportAction?: ReportAction, - policyTags?: OnyxEntry, - policy?: OnyxEntry, -): string | undefined { +function computeChatThreadReportName({ + translate, + convertToDisplayString, + getCurrencySymbol, + isArchived, + report, + reports, + currentUserLogin, + transactions, + parentReportAction, + policyTags, + policy, +}: { + translate: LocalizedTranslate; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; + getCurrencySymbol: CurrencyListActionsContextType['getCurrencySymbol']; + isArchived: boolean; + report: Report; + reports: OnyxCollection; + currentUserLogin: string; + transactions: OnyxCollection; + parentReportAction?: ReportAction; + policyTags?: OnyxEntry; + policy?: OnyxEntry; +}): string | undefined { if (!isChatThread(report)) { return undefined; } @@ -989,7 +1009,6 @@ function computeChatThreadReportName( const linkedTransactionReport = linkedTransaction?.reportID ? reports?.[`${ONYXKEYS.COLLECTION.REPORT}${linkedTransaction.reportID}`] : undefined; let formattedName = getTransactionReportName({ translate, - // Non-React call path: pass the standalone utils until this file's own currency-context threading PR. convertToDisplayString, getCurrencySymbol, reportAction: parentReportAction, @@ -1031,7 +1050,6 @@ function computeChatThreadReportName( const movedToReport = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(parentReportAction, CONST.REPORT.MOVE_TYPE.TO)}`]; const modifiedMessageWithHTML = getForReportAction({ translate, - // Non-React call path: pass the standalone util until this file's own convertToDisplayString threading PR. convertToDisplayString, reportAction: parentReportAction, movedFromReport, @@ -1071,6 +1089,9 @@ function computeReportName({ reportAttributes, reportTransactions, isTrackIntentUser, + convertToDisplayString, + convertToDisplayStringWithoutCurrency, + getCurrencySymbol, pendingDeleteMemberAccountIDs, }: ComputeReportName): string { if (!report?.reportID) { @@ -1093,6 +1114,8 @@ function computeReportName({ reportAttributes, isTrackIntentUser, currentUserAccountID: currentUserAccountID ?? CONST.DEFAULT_NUMBER_ID, + convertToDisplayString, + convertToDisplayStringWithoutCurrency, }); if (parentReportActionBasedName) { @@ -1122,6 +1145,9 @@ function computeReportName({ reportAttributes, reportTransactions, isTrackIntentUser, + convertToDisplayString, + convertToDisplayStringWithoutCurrency, + getCurrencySymbol, // TODO: pass the true data in the next PR, issue https://github.com/Expensify/App/issues/66421 pendingDeleteMemberAccountIDs: undefined, }); @@ -1137,17 +1163,19 @@ function computeReportName({ const privateIsArchivedValue = !!allReportNameValuePairs?.[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${report.reportID}`]?.private_isArchived; const policyTags = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report.policyID}`]; - const chatThreadReportName = computeChatThreadReportName( + const chatThreadReportName = computeChatThreadReportName({ translate, - privateIsArchivedValue, + convertToDisplayString, + getCurrencySymbol, + isArchived: privateIsArchivedValue, report, - reports ?? {}, - currentUserLogin ?? '', + reports: reports ?? {}, + currentUserLogin: currentUserLogin ?? '', transactions, parentReportAction, policyTags, - reportPolicy, - ); + policy: reportPolicy, + }); if (chatThreadReportName) { return chatThreadReportName; } @@ -1178,6 +1206,7 @@ function computeReportName({ linkedTransactions: reportTransactions[report.reportID] ?? [], personalDetailsList, translate, + convertToDisplayString, }); } @@ -1189,7 +1218,7 @@ function computeReportName({ chatReceiverPolicyID = (chatReceiver as {policyID: string}).policyID; } const invoiceReceiverPolicy = chatReceiverPolicyID ? policies?.[`${ONYXKEYS.COLLECTION.POLICY}${chatReceiverPolicyID}`] : undefined; - formattedName = getInvoiceReportName(report, reportTransactions[report.reportID] ?? [], translate, personalDetailsList, policy, invoiceReceiverPolicy); + formattedName = getInvoiceReportName(report, reportTransactions[report.reportID] ?? [], translate, convertToDisplayString, personalDetailsList, policy, invoiceReceiverPolicy); } if (isInvoiceRoom(report)) { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 6efa65d8eff7..3df1c212aa43 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -13662,6 +13662,7 @@ function getChatListItemReportName( conciergeReportID: string | undefined, linkedTransactions: Transaction[], translate: LocalizedTranslate, + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString'], personalDetailsList: OnyxEntry, ): string { const reportForHeader = getReportForHeader(report, parentReport); @@ -13669,7 +13670,7 @@ function getChatListItemReportName( // Search snapshots of invoice reports may only carry `parentReportID` as the invoice room ID, so fall back to it // when `chatReportID` is missing (without mutating the Onyx report) so `getInvoiceReportName` resolves the NewDot title. const invoiceReport = reportForHeader.chatReportID ? reportForHeader : {...reportForHeader, chatReportID: reportForHeader.parentReportID}; - return getInvoiceReportName(invoiceReport, linkedTransactions, translate, personalDetailsList); + return getInvoiceReportName(invoiceReport, linkedTransactions, translate, convertToDisplayString, personalDetailsList); } if (action?.reportName) { diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 6cf4f48ad082..46d393ff5cd5 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -699,6 +699,7 @@ function getOptionData({ translate, dateFnsLocale, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, isReportArchived, lastActionReport, @@ -727,6 +728,7 @@ function getOptionData({ translate: LocalizedTranslate; dateFnsLocale: DateFnsLocale | undefined; convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; + convertToDisplayStringWithoutCurrency: CurrencyListActionsContextType['convertToDisplayStringWithoutCurrency']; localeCompare: LocaleContextProps['localeCompare']; isReportArchived: boolean | undefined; lastActionReport: OnyxEntry; @@ -891,6 +893,7 @@ function getOptionData({ formatPhoneNumber, dateFnsLocale, convertToDisplayString, + convertToDisplayStringWithoutCurrency, }); result.isIOUReportOwner = isIOUOwnedByCurrentUser(result as Report); diff --git a/src/libs/actions/IOU/MoneyRequest.ts b/src/libs/actions/IOU/MoneyRequest.ts index b6fd46e96813..cbb65d62be59 100644 --- a/src/libs/actions/IOU/MoneyRequest.ts +++ b/src/libs/actions/IOU/MoneyRequest.ts @@ -268,18 +268,33 @@ function createTransaction({ } } -function getMoneyRequestParticipantOptions( - currentUserAccountID: number, - report: OnyxEntry, - policy: OnyxEntry, - personalDetails: OnyxEntry, - conciergeReportID: string | undefined, - privateIsArchived: boolean | undefined, - reportAttributesDerived: ReportAttributesDerivedValue['reports'] | undefined, - reportDraft: OnyxEntry | undefined, - translate: LocalizedTranslate, - dateFnsLocale: DateFnsLocale | undefined, -): Array { +type GetMoneyRequestParticipantOptionsParams = { + currentUserAccountID: number; + report: OnyxEntry; + policy: OnyxEntry; + personalDetails: OnyxEntry; + conciergeReportID: string | undefined; + privateIsArchived: boolean | undefined; + reportAttributesDerived: ReportAttributesDerivedValue['reports'] | undefined; + reportDraft: OnyxEntry | undefined; + translate: LocalizedTranslate; + convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; + dateFnsLocale: DateFnsLocale | undefined; +}; + +function getMoneyRequestParticipantOptions({ + currentUserAccountID, + report, + policy, + personalDetails, + conciergeReportID, + privateIsArchived, + reportAttributesDerived, + reportDraft, + translate, + convertToDisplayString, + dateFnsLocale, +}: GetMoneyRequestParticipantOptionsParams): Array { const selectedParticipants = getMoneyRequestParticipantsFromReport(report, currentUserAccountID); return selectedParticipants.map((participant) => { const participantAccountID = participant?.accountID ?? CONST.DEFAULT_NUMBER_ID; @@ -288,6 +303,7 @@ function getMoneyRequestParticipantOptions( : getReportOption(participant, privateIsArchived, policy, personalDetails, conciergeReportID, reportAttributesDerived, reportDraft, currentUserAccountID, { translate, dateFnsLocale, + convertToDisplayString, }); }); } diff --git a/src/libs/actions/OnyxDerived/configs/reportAttributes.ts b/src/libs/actions/OnyxDerived/configs/reportAttributes.ts index c178b2c8ff11..137bda1ce48a 100644 --- a/src/libs/actions/OnyxDerived/configs/reportAttributes.ts +++ b/src/libs/actions/OnyxDerived/configs/reportAttributes.ts @@ -1,8 +1,12 @@ import type {LocalizedTranslate} from '@components/LocaleContextProvider'; +import type {CurrencyListActionsContextType} from '@hooks/useCurrencyList'; + import {getReportPreviewReportAction} from '@libs/actions/IOU/MoneyRequestBuilder'; +import {convertToFrontendAmountAsInteger, sanitizeCurrencyCode} from '@libs/CurrencyUtils'; import {translate as translateForLocale} from '@libs/Localize'; import {getIsOffline} from '@libs/NetworkState'; +import {format, formatToParts} from '@libs/NumberFormatUtils'; import {getLoginByAccountID} from '@libs/PersonalDetailsUtils'; import {isPolicyFieldListEmpty} from '@libs/PolicyUtils'; import {getLinkedTransactionID, isDeletedAction} from '@libs/ReportActionsUtils'; @@ -226,6 +230,7 @@ export default createOnyxDerivedValueConfig({ ONYXKEYS.CONCIERGE_REPORT_ID, ONYXKEYS.NVP_INTRO_SELECTED, ONYXKEYS.COLLECTION.REPORT_METADATA, + ONYXKEYS.CURRENCY_LIST, ONYXKEYS.NETWORK, ], compute: ( @@ -243,6 +248,7 @@ export default createOnyxDerivedValueConfig({ conciergeReportID, introSelected, reportMetadata, + currencyList, ], {currentValue, sourceValues, triggeredKeys}, ) => { @@ -250,6 +256,40 @@ export default createOnyxDerivedValueConfig({ const isOffline = getIsOffline(); const dateFnsLocale = IntlStore.getDateFnsLocale(preferredLocale); const translate: LocalizedTranslate = (path, ...parameters) => translateForLocale(preferredLocale, path, ...parameters); + // Non-React computation: there is no component to inject the currency formatters from CurrencyListContextProvider, + // so mirror the provider's implementations here using the CURRENCY_LIST dependency and the preferred locale. + const getCurrencyDecimals = (currencyCode: string): number => currencyList?.[currencyCode]?.decimals ?? CONST.DEFAULT_CURRENCY_DECIMALS; + const getCurrencySymbol: CurrencyListActionsContextType['getCurrencySymbol'] = (currencyCode) => currencyList?.[currencyCode]?.symbol; + const convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString'] = (amountInCents, currencyCode) => { + const sanitizedCurrency = sanitizeCurrencyCode(currencyCode); + const decimals = getCurrencyDecimals(sanitizedCurrency); + const convertedAmount = convertToFrontendAmountAsInteger(amountInCents ?? 0, decimals); + return format(preferredLocale, convertedAmount, { + style: 'currency', + currency: sanitizedCurrency, + + // 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, + }); + }; + const convertToDisplayStringWithoutCurrency: CurrencyListActionsContextType['convertToDisplayStringWithoutCurrency'] = (amountInCents, currencyCode = CONST.CURRENCY.USD) => { + const sanitizedCurrency = sanitizeCurrencyCode(currencyCode); + const decimals = getCurrencyDecimals(sanitizedCurrency); + const convertedAmount = convertToFrontendAmountAsInteger(amountInCents, decimals); + return formatToParts(preferredLocale, convertedAmount, { + style: 'currency', + currency: sanitizedCurrency, + minimumFractionDigits: decimals, + maximumFractionDigits: 2, + }) + .filter((x) => x.type !== 'currency') + .filter((x) => x.type !== 'literal' || x.value.trim().length !== 0) + .map((x) => x.value) + .join(''); + }; // Check if display names changed when personal details are updated let displayNameChanges: Set | typeof RECOMPUTE_ALL | null = null; if (hasKeyTriggeredCompute(ONYXKEYS.PERSONAL_DETAILS_LIST, triggeredKeys)) { @@ -282,7 +322,10 @@ export default createOnyxDerivedValueConfig({ (hasKeyTriggeredCompute(ONYXKEYS.NVP_PREFERRED_LOCALE, triggeredKeys) && preferredLocale !== currentValue?.locale) || displayNameChanges === RECOMPUTE_ALL || hasKeyTriggeredCompute(ONYXKEYS.CONCIERGE_REPORT_ID, triggeredKeys) || - hasKeyTriggeredCompute(ONYXKEYS.NVP_INTRO_SELECTED, triggeredKeys); + hasKeyTriggeredCompute(ONYXKEYS.NVP_INTRO_SELECTED, triggeredKeys) || + // Amount-bearing report names format with the currency list's decimals/symbols, so names computed before + // the list arrived (or with a stale list) must all be redone. This loads roughly once per session. + hasKeyTriggeredCompute(ONYXKEYS.CURRENCY_LIST, triggeredKeys); const policyChangedReportKeys: string[] = []; // Reports whose policy change touched only fields that don't feed the report name (type, approvalMode, @@ -644,6 +687,9 @@ export default createOnyxDerivedValueConfig({ reportAttributes: currentValue?.reports, reportTransactions: reportsTransactions ?? {}, isTrackIntentUser: isTrackIntentUserSelector(introSelected), + convertToDisplayString, + convertToDisplayStringWithoutCurrency, + getCurrencySymbol, pendingDeleteMemberAccountIDs, }), isEmpty: generateIsEmptyReport(report, isReportArchived), diff --git a/src/pages/NewChatPage/useGroupChatDraftParticipantSync.ts b/src/pages/NewChatPage/useGroupChatDraftParticipantSync.ts index 5dafb8224daa..05c8a11bfcbe 100644 --- a/src/pages/NewChatPage/useGroupChatDraftParticipantSync.ts +++ b/src/pages/NewChatPage/useGroupChatDraftParticipantSync.ts @@ -1,5 +1,6 @@ import type {LocalizedTranslate} from '@components/LocaleContextProvider'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useIsFocusedRef from '@hooks/useIsFocusedRef'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; @@ -39,6 +40,7 @@ function useGroupChatDraftParticipantSync( const isScreenFocusedRef = useIsFocusedRef(); const {dateFnsLocale} = useLocalize(); + const {convertToDisplayString} = useCurrencyListActions(); const draftParticipantsSelector = (draft: NewGroupChatDraft | undefined) => { const isSubscriptionActive = shouldRestoreSelectedOptionsRef.current || !isScreenFocusedRef.current; return isSubscriptionActive ? draft?.participants : undefined; @@ -65,6 +67,7 @@ function useGroupChatDraftParticipantSync( (getParticipantsOption({accountID: participant.accountID, login: participant.login}, allPersonalDetails, translate) as OptionData) : getUserToInviteOption({ dateFnsLocale, + convertToDisplayString, searchValue: participant?.login, personalDetails: allPersonalDetails, loginList, diff --git a/src/pages/ReportSubmitToContent.tsx b/src/pages/ReportSubmitToContent.tsx index 0bfed8ec2d5e..53877b734fd8 100644 --- a/src/pages/ReportSubmitToContent.tsx +++ b/src/pages/ReportSubmitToContent.tsx @@ -80,7 +80,7 @@ function ReportSubmitToContent({ }: ReportSubmitToContentProps) { const styles = useThemeStyles(); const {translate, localeCompare, dateFnsLocale} = useLocalize(); - const {getCurrencyDecimals} = useCurrencyListActions(); + const {getCurrencyDecimals, convertToDisplayString} = useCurrencyListActions(); const isInLandscapeMode = useIsInLandscapeMode(); const {shouldUseNarrowLayout} = useResponsiveLayout(); const {keyboardActiveHeight, isKeyboardActive} = useKeyboardState(); @@ -211,6 +211,7 @@ function ReportSubmitToContent({ const inviteOption = getUserToInviteOption({ dateFnsLocale, + convertToDisplayString, searchValue: trimmed, personalDetails, loginList, @@ -231,7 +232,7 @@ function ReportSubmitToContent({ keyForList: `nonWorkspace:${login}`, isSelected: managerEmail.trim().toLowerCase() === login.trim().toLowerCase(), }; - }, [countryCode, currentUserDetails.email, searchTerm, filteredWorkspaceMembers.length, loginList, managerEmail, personalDetails, dateFnsLocale]); + }, [countryCode, currentUserDetails.email, searchTerm, filteredWorkspaceMembers.length, loginList, managerEmail, personalDetails, dateFnsLocale, convertToDisplayString]); const submitToSelectionData = useMemo(() => { if (!nonWorkspaceInviteRow) { diff --git a/src/pages/Share/ShareDetailsPage.tsx b/src/pages/Share/ShareDetailsPage.tsx index 6f132d8769b1..60737c267106 100644 --- a/src/pages/Share/ShareDetailsPage.tsx +++ b/src/pages/Share/ShareDetailsPage.tsx @@ -9,6 +9,7 @@ import Text from '@components/Text'; import TextInput from '@components/TextInput'; import useAncestors from '@hooks/useAncestors'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDelegateAccountID from '@hooks/useDelegateAccountID'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; @@ -60,6 +61,7 @@ function ShareDetailsPage({route}: ShareDetailsPageProps) { const icons = useMemoizedLazyExpensifyIcons(['FallbackAvatar']); const styles = useThemeStyles(); const {translate, dateFnsLocale} = useLocalize(); + const {convertToDisplayString} = useCurrencyListActions(); const [unknownUserDetails] = useOnyx(ONYXKEYS.SHARE_UNKNOWN_USER_DETAILS); const [currentAttachment] = useOnyx(ONYXKEYS.SHARE_TEMP_FILE); const [validatedFile] = useOnyx(ONYXKEYS.VALIDATED_FILE_OBJECT); @@ -89,6 +91,7 @@ function ShareDetailsPage({route}: ShareDetailsPageProps) { () => getReportDisplayOption({ dateFnsLocale, + convertToDisplayString, report, unknownUserDetails, personalDetails, @@ -99,7 +102,19 @@ function ShareDetailsPage({route}: ShareDetailsPageProps) { currentUserAccountID, reportAttributesDerived, }), - [report, unknownUserDetails, personalDetails, privateIsArchived, policy, conciergeReportID, translate, currentUserAccountID, reportAttributesDerived, dateFnsLocale], + [ + report, + unknownUserDetails, + personalDetails, + privateIsArchived, + policy, + conciergeReportID, + translate, + currentUserAccountID, + reportAttributesDerived, + dateFnsLocale, + convertToDisplayString, + ], ); const shouldShowAttachment = !isTextShared; diff --git a/src/pages/Share/ShareTab.tsx b/src/pages/Share/ShareTab.tsx index ea980e7fad8c..5766c3757bd1 100644 --- a/src/pages/Share/ShareTab.tsx +++ b/src/pages/Share/ShareTab.tsx @@ -3,6 +3,7 @@ import SelectionList from '@components/SelectionList'; import InviteMemberListItem from '@components/SelectionList/ListItem/InviteMemberListItem'; import Text from '@components/Text'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDebouncedState from '@hooks/useDebouncedState'; import useFilteredOptions from '@hooks/useFilteredOptions'; @@ -40,6 +41,7 @@ const defaultListOptions = { function ShareTab() { const styles = useThemeStyles(); const {translate, dateFnsLocale} = useLocalize(); + const {convertToDisplayString} = useCurrencyListActions(); const {isOffline} = useNetwork(); const [textInputValue, debouncedTextInputValue, setTextInputValue] = useDebouncedState(''); const [betas] = useOnyx(ONYXKEYS.BETAS); @@ -72,6 +74,7 @@ function ShareTab() { const searchOptions = areOptionsInitialized ? getSearchOptions({ dateFnsLocale, + convertToDisplayString, options: listOptions ?? {reports: [], personalDetails: []}, draftComments, betas: betas ?? [], diff --git a/src/pages/Share/SubmitDetailsPage.tsx b/src/pages/Share/SubmitDetailsPage.tsx index 75d56ba522fa..cf551caabf73 100644 --- a/src/pages/Share/SubmitDetailsPage.tsx +++ b/src/pages/Share/SubmitDetailsPage.tsx @@ -85,7 +85,7 @@ function SubmitDetailsPage({ }: ShareDetailsPageProps) { const styles = useThemeStyles(); const {translate, dateFnsLocale, formatPhoneNumber} = useLocalize(); - const {getCurrencyDecimals} = useCurrencyListActions(); + const {getCurrencyDecimals, convertToDisplayString} = useCurrencyListActions(); const delegateAccountID = useDelegateAccountID(); const [unknownUserDetails] = useOnyx(ONYXKEYS.SHARE_UNKNOWN_USER_DETAILS); const [personalDetails] = useOnyx(`${ONYXKEYS.PERSONAL_DETAILS_LIST}`); @@ -231,6 +231,7 @@ function SubmitDetailsPage({ : getReportOption(participant, privateIsArchived, policy, personalDetails, conciergeReportID, reportAttributesDerived, reportDraft, currentUserPersonalDetails.accountID, { translate, dateFnsLocale, + convertToDisplayString, }); }); diff --git a/src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx index a9abc0e3af29..5b3c074f8721 100755 --- a/src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -167,7 +167,7 @@ function BaseReportActionContextMenu({ ]); const StyleUtils = useStyleUtils(); const {translate, getLocalDateFromDatetime, formatPhoneNumber, dateFnsLocale} = useLocalize(); - const {convertToDisplayString} = useCurrencyListActions(); + const {convertToDisplayString, convertToDisplayStringWithoutCurrency} = useCurrencyListActions(); // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout(); const [shouldKeepOpen, setShouldKeepOpen] = useState(false); @@ -426,6 +426,7 @@ function BaseReportActionContextMenu({ translate, dateFnsLocale, convertToDisplayString, + convertToDisplayStringWithoutCurrency, formatPhoneNumber, harvestReport, harvestReportOriginalID, diff --git a/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx b/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx index 89d3c37ef9f5..ccf48f01e6c4 100644 --- a/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx +++ b/src/pages/inbox/report/ContextMenu/ContextMenuActions.tsx @@ -347,6 +347,7 @@ type ContextMenuActionPayload = { translate: LocalizedTranslate; dateFnsLocale: LocaleContextProps['dateFnsLocale']; convertToDisplayString: CurrencyListActionsContextType['convertToDisplayString']; + convertToDisplayStringWithoutCurrency: CurrencyListActionsContextType['convertToDisplayStringWithoutCurrency']; formatPhoneNumber: LocaleContextProps['formatPhoneNumber']; harvestReport?: OnyxEntry; harvestReportOriginalID?: string; @@ -1011,6 +1012,7 @@ const ContextMenuActions: ContextMenuAction[] = [ translate, dateFnsLocale, convertToDisplayString, + convertToDisplayStringWithoutCurrency, formatPhoneNumber, harvestReport, harvestReportOriginalID, @@ -1430,7 +1432,7 @@ const ContextMenuActions: ContextMenuAction[] = [ } else if (isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_CARD_FRAUD_ALERT)) { setClipboardMessage(getActionableCardFraudAlertMessage(translate, dateFnsLocale, reportAction, getLocalDateFromDatetime, convertToDisplayString)); } else if (isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_CARD_3DS_TRANSACTION_APPROVAL)) { - setClipboardMessage(getActionableCard3DSTransactionApprovalMessage(translate, reportAction)); + setClipboardMessage(getActionableCard3DSTransactionApprovalMessage(translate, reportAction, convertToDisplayString, convertToDisplayStringWithoutCurrency)); } else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CHANGE_POLICY) { const displayMessage = getPolicyChangeMessage(translate, reportAction); Clipboard.setString(displayMessage); diff --git a/src/pages/inbox/report/SearchActionHeader.tsx b/src/pages/inbox/report/SearchActionHeader.tsx index 64e0219b54db..c7fa693c4358 100644 --- a/src/pages/inbox/report/SearchActionHeader.tsx +++ b/src/pages/inbox/report/SearchActionHeader.tsx @@ -3,6 +3,7 @@ import {useIsOnSearch} from '@components/Search/SearchScopeProvider'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useReportTransactionsCollection from '@hooks/useReportTransactionsCollection'; @@ -37,6 +38,7 @@ type SearchActionHeaderProps = { function SearchActionHeaderContent({action, report, isWhisper, onPress, children}: SearchActionHeaderProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); + const {convertToDisplayString} = useCurrencyListActions(); const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID); const personalDetailsList = usePersonalDetails(); const parentReportID = isChatThread(report) ? report.parentReportID : undefined; @@ -50,7 +52,7 @@ function SearchActionHeaderContent({action, report, isWhisper, onPress, children const reportTransactionsCollection = useReportTransactionsCollection(reportForHeaderReportID); const linkedTransactions = Object.values(reportTransactionsCollection ?? {}).filter((transaction): transaction is Transaction => !!transaction); - const reportName = getChatListItemReportName(action, report, parentReport, conciergeReportID, linkedTransactions, translate, personalDetailsList); + const reportName = getChatListItemReportName(action, report, parentReport, conciergeReportID, linkedTransactions, translate, convertToDisplayString, personalDetailsList); return ( diff --git a/src/pages/inbox/report/actionContents/SimpleMessageContent.tsx b/src/pages/inbox/report/actionContents/SimpleMessageContent.tsx index 5b2862fe4c44..c929fca11b36 100644 --- a/src/pages/inbox/report/actionContents/SimpleMessageContent.tsx +++ b/src/pages/inbox/report/actionContents/SimpleMessageContent.tsx @@ -51,7 +51,7 @@ function isSimpleMessageAction(action: OnyxTypes.ReportAction): boolean { function SimpleMessageContent({action}: SimpleMessageContentProps) { const {translate} = useLocalize(); - const {convertToDisplayString} = useCurrencyListActions(); + const {convertToDisplayString, convertToDisplayStringWithoutCurrency} = useCurrencyListActions(); if (isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.MARKED_REIMBURSED)) { return ; @@ -102,7 +102,7 @@ function SimpleMessageContent({action}: SimpleMessageContentProps) { return ; } if (isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.ACTIONABLE_CARD_3DS_TRANSACTION_APPROVAL)) { - return ; + return ; } if (isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.MARK_REIMBURSED_FROM_INTEGRATION)) { return ; diff --git a/src/pages/iou/DynamicSplitBillDetailsPage.tsx b/src/pages/iou/DynamicSplitBillDetailsPage.tsx index 254a3a6a5f39..91639cb7a5e1 100644 --- a/src/pages/iou/DynamicSplitBillDetailsPage.tsx +++ b/src/pages/iou/DynamicSplitBillDetailsPage.tsx @@ -53,7 +53,7 @@ type SplitBillDetailsPageProps = WithReportAndReportActionOrNotFoundProps & Plat function DynamicSplitBillDetailsPage({report, reportAction}: SplitBillDetailsPageProps) { const styles = useThemeStyles(); const {translate, formatPhoneNumber, dateFnsLocale} = useLocalize(); - const {getCurrencyDecimals, getCurrencySymbol} = useCurrencyListActions(); + const {getCurrencyDecimals, getCurrencySymbol, convertToDisplayString} = useCurrencyListActions(); const theme = useTheme(); const {isBetaEnabled} = usePermissions(); const icons = useMemoizedLazyExpensifyIcons(['ReceiptScan']); @@ -87,7 +87,7 @@ function DynamicSplitBillDetailsPage({report, reportAction}: SplitBillDetailsPag personalDetails, report, policy, - {translate, dateFnsLocale}, + {translate, dateFnsLocale, convertToDisplayString}, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, reportAttributesDerived, ), diff --git a/src/pages/iou/request/ParticipantSearchResults.tsx b/src/pages/iou/request/ParticipantSearchResults.tsx index ec6f39bc96c1..16d77903a646 100644 --- a/src/pages/iou/request/ParticipantSearchResults.tsx +++ b/src/pages/iou/request/ParticipantSearchResults.tsx @@ -8,6 +8,7 @@ import type {Section, SelectionListWithSectionsHandle} from '@components/Selecti import useContactImport from '@hooks/useContactImport'; import useContactPermissionModal from '@hooks/useContactPermissionModal'; +import {useCurrencyListActions} from '@hooks/useCurrencyList'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useDismissedReferralBanners from '@hooks/useDismissedReferralBanners'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; @@ -164,6 +165,7 @@ function ParticipantSearchResults({ action !== CONST.IOU.ACTION.CATEGORIZE; const icons = useMemoizedLazyExpensifyIcons(['UserPlus']); const {translate, dateFnsLocale} = useLocalize(); + const {convertToDisplayString} = useCurrencyListActions(); const {contactPermissionState, contacts, setContactPermissionState} = useContactImport(); const {isOffline} = useNetwork(); const personalDetails = usePersonalDetails(); @@ -319,6 +321,7 @@ function ParticipantSearchResults({ currentUserAccountID, allPolicies, translate, + convertToDisplayString, dateFnsLocale, personalDetails, true, @@ -395,7 +398,7 @@ function ParticipantSearchResults({ personalDetails, userToInviteExpenseReport, userToInviteExpenseReportPolicy, - {translate, dateFnsLocale}, + {translate, dateFnsLocale, convertToDisplayString}, currentUserAccountID, reportAttributesDerived, ) diff --git a/src/pages/iou/request/step/IOURequestStepAmount.tsx b/src/pages/iou/request/step/IOURequestStepAmount.tsx index 498663cf4609..305250768295 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.tsx +++ b/src/pages/iou/request/step/IOURequestStepAmount.tsx @@ -76,7 +76,7 @@ function IOURequestStepAmount({ }: IOURequestStepAmountProps) { const {translate, dateFnsLocale, formatPhoneNumber} = useLocalize(); const {isOffline} = useNetwork(); - const {getCurrencyDecimals, getCurrencySymbol} = useCurrencyListActions(); + const {getCurrencyDecimals, getCurrencySymbol, convertToDisplayString} = useCurrencyListActions(); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const [isCurrencyPickerVisible, setIsCurrencyPickerVisible] = useState(false); const textInput = useRef(null); @@ -232,6 +232,7 @@ function IOURequestStepAmount({ : getReportOption(participant, privateIsArchived, policy, personalDetails, conciergeReportID, reportAttributesDerived, reportDraft, currentUserPersonalDetails.accountID, { translate, dateFnsLocale, + convertToDisplayString, }); }); const participant = participants.at(0); @@ -253,6 +254,7 @@ function IOURequestStepAmount({ submitAmount({ getCurrencyDecimals, getCurrencySymbol, + convertToDisplayString, translate, dateFnsLocale, report, diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index f059484428cb..19667fb9ddab 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -136,7 +136,7 @@ function IOURequestStepConfirmationContent({ shouldHideHeader = false, navigation, }: IOURequestStepConfirmationProps) { - const {getCurrencyDecimals} = useCurrencyListActions(); + const {getCurrencyDecimals, convertToDisplayString} = useCurrencyListActions(); const params = route.params; const {iouType, reportID, transactionID: initialTransactionID, action, backToReport, backTo} = params; const participantsAutoAssignedFromRoute = route.name === SCREENS.MONEY_REQUEST.STEP_CONFIRMATION ? (params as StepConfirmationParams).participantsAutoAssigned : undefined; @@ -321,7 +321,7 @@ function IOURequestStepConfirmationContent({ reportAttributesDerived, participantReportDraft, currentUserPersonalDetails.accountID, - {translate, dateFnsLocale}, + {translate, dateFnsLocale, convertToDisplayString}, ); }) ?? [], [ @@ -336,6 +336,7 @@ function IOURequestStepConfirmationContent({ conciergeReportID, reportDrafts, translate, + convertToDisplayString, currentUserPersonalDetails.accountID, ], ); diff --git a/src/pages/iou/request/step/IOURequestStepScan/components/ScanSkipConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepScan/components/ScanSkipConfirmation.tsx index 54e912f067df..023f11aa0991 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/components/ScanSkipConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/components/ScanSkipConfirmation.tsx @@ -116,24 +116,25 @@ function ScanSkipConfirmation({report, action, iouType, reportID, transactionID, const [transactions] = useOptimisticDraftTransactions(transaction); const {isMultiScanEnabled} = useMultiScanState(); const {translate, formatPhoneNumber, dateFnsLocale} = useLocalize(); - const {getCurrencyDecimals} = useCurrencyListActions(); + const {convertToDisplayString, getCurrencyDecimals} = useCurrencyListActions(); const {disableMultiScan} = useMultiScanActions(); const {setIsLoaderVisible} = useFullScreenLoaderActions(); const [startLocationPermissionFlow, setStartLocationPermissionFlow] = useState(false); const [receiptFiles, setReceiptFiles] = useState([]); - const participants = getMoneyRequestParticipantOptions( - currentUserPersonalDetails.accountID, + const participants = getMoneyRequestParticipantOptions({ + currentUserAccountID: currentUserPersonalDetails.accountID, report, policy, personalDetails, conciergeReportID, - isArchived, + privateIsArchived: isArchived, reportAttributesDerived, reportDraft, translate, + convertToDisplayString, dateFnsLocale, - ); + }); const participantsPolicyTags = useParticipantsPolicyTags(participants); // Whether this expense's sole destination is the current user's self-DM. Forwarded to the cleanup helpers so the diff --git a/tests/actions/IOU/MoneyRequestTest.ts b/tests/actions/IOU/MoneyRequestTest.ts index b739ccc61374..b1a87d1bf5d3 100644 --- a/tests/actions/IOU/MoneyRequestTest.ts +++ b/tests/actions/IOU/MoneyRequestTest.ts @@ -29,7 +29,7 @@ import createRandomPolicy from '../../utils/collections/policies'; import {createRandomReport, createSelfDM} from '../../utils/collections/reports'; import createRandomTransaction from '../../utils/collections/transaction'; import getOnyxValue from '../../utils/getOnyxValue'; -import {formatPhoneNumber, getCurrencyDecimalsLocal, getCurrencySymbolLocal, translateLocal} from '../../utils/TestHelper'; +import {convertToDisplayString, formatPhoneNumber, getCurrencyDecimalsLocal, getCurrencySymbolLocal, translateLocal} from '../../utils/TestHelper'; import waitForBatchedUpdates from '../../utils/waitForBatchedUpdates'; jest.mock('@libs/actions/IOU', () => { @@ -796,7 +796,19 @@ describe('MoneyRequest', () => { isTrackIntentUser: false, formatPhoneNumber, delegateAccountID: undefined, - participants: getMoneyRequestParticipantOptions(1, fakeReport, fakePolicy, {}, undefined, false, {}, undefined, translateLocal, undefined), + participants: getMoneyRequestParticipantOptions({ + currentUserAccountID: 1, + report: fakeReport, + policy: fakePolicy, + personalDetails: {}, + conciergeReportID: undefined, + privateIsArchived: false, + reportAttributesDerived: {}, + reportDraft: undefined, + translate: translateLocal, + convertToDisplayString, + dateFnsLocale: undefined, + }), participantsPolicyTags: {}, }; const splitShares: SplitShares = { @@ -1712,39 +1724,53 @@ describe('MoneyRequest', () => { }); it('should return participants when conciergeReportID is undefined', () => { - const participants = getMoneyRequestParticipantOptions(currentUserAccountID, fakeReport, fakePolicy, {}, undefined, undefined, undefined, undefined, translateLocal, undefined); + const participants = getMoneyRequestParticipantOptions({ + currentUserAccountID, + report: fakeReport, + policy: fakePolicy, + personalDetails: {}, + conciergeReportID: undefined, + privateIsArchived: undefined, + reportAttributesDerived: undefined, + reportDraft: undefined, + translate: translateLocal, + convertToDisplayString, + dateFnsLocale: undefined, + }); expect(Array.isArray(participants)).toBe(true); }); it('should return participants when conciergeReportID is provided', () => { - const participants = getMoneyRequestParticipantOptions( + const participants = getMoneyRequestParticipantOptions({ currentUserAccountID, - fakeReport, - fakePolicy, - {}, - 'concierge123', - undefined, - undefined, - undefined, - translateLocal, - undefined, - ); + report: fakeReport, + policy: fakePolicy, + personalDetails: {}, + conciergeReportID: 'concierge123', + privateIsArchived: undefined, + reportAttributesDerived: undefined, + reportDraft: undefined, + translate: translateLocal, + convertToDisplayString, + dateFnsLocale: undefined, + }); expect(Array.isArray(participants)).toBe(true); }); it('should pass conciergeReportID through to getReportOption for policy expense chat participants', () => { - const participants = getMoneyRequestParticipantOptions( + const participants = getMoneyRequestParticipantOptions({ currentUserAccountID, - fakeReport, - fakePolicy, - {}, - 'concierge456', - undefined, - undefined, - undefined, - translateLocal, - undefined, - ); + report: fakeReport, + policy: fakePolicy, + personalDetails: {}, + conciergeReportID: 'concierge456', + privateIsArchived: undefined, + reportAttributesDerived: undefined, + reportDraft: undefined, + translate: translateLocal, + convertToDisplayString, + dateFnsLocale: undefined, + }); // For policy expense chat, participants have accountID 0 and go through getReportOption // which uses conciergeReportID for identifying concierge chat expect(Array.isArray(participants)).toBe(true); @@ -1752,7 +1778,19 @@ describe('MoneyRequest', () => { }); it('should return participants with privateIsArchived passed through', () => { - const participants = getMoneyRequestParticipantOptions(currentUserAccountID, fakeReport, fakePolicy, {}, undefined, true, undefined, undefined, translateLocal, undefined); + const participants = getMoneyRequestParticipantOptions({ + currentUserAccountID, + report: fakeReport, + policy: fakePolicy, + personalDetails: {}, + conciergeReportID: undefined, + privateIsArchived: true, + reportAttributesDerived: undefined, + reportDraft: undefined, + translate: translateLocal, + convertToDisplayString, + dateFnsLocale: undefined, + }); expect(Array.isArray(participants)).toBe(true); }); @@ -1761,26 +1799,74 @@ describe('MoneyRequest', () => { ...createRandomReport(2, undefined), participants: {}, }; - const participants = getMoneyRequestParticipantOptions(currentUserAccountID, dmReport, fakePolicy, {}, undefined, undefined, undefined, undefined, translateLocal, undefined); + const participants = getMoneyRequestParticipantOptions({ + currentUserAccountID, + report: dmReport, + policy: fakePolicy, + personalDetails: {}, + conciergeReportID: undefined, + privateIsArchived: undefined, + reportAttributesDerived: undefined, + reportDraft: undefined, + translate: translateLocal, + convertToDisplayString, + dateFnsLocale: undefined, + }); expect(Array.isArray(participants)).toBe(true); }); it('should mark policy expense chat participant as disabled when reportDrafts contains the report', () => { - const participants = getMoneyRequestParticipantOptions(currentUserAccountID, fakeReport, fakePolicy, {}, undefined, undefined, undefined, fakeReport, translateLocal, undefined); + const participants = getMoneyRequestParticipantOptions({ + currentUserAccountID, + report: fakeReport, + policy: fakePolicy, + personalDetails: {}, + conciergeReportID: undefined, + privateIsArchived: undefined, + reportAttributesDerived: undefined, + reportDraft: fakeReport, + translate: translateLocal, + convertToDisplayString, + dateFnsLocale: undefined, + }); expect(Array.isArray(participants)).toBe(true); expect(participants.length).toBeGreaterThan(0); expect(participants.at(0)).toMatchObject({isDisabled: true}); }); it('should not mark participant as disabled when reportDraft is undefined', () => { - const participants = getMoneyRequestParticipantOptions(currentUserAccountID, fakeReport, fakePolicy, {}, undefined, undefined, undefined, undefined, translateLocal, undefined); + const participants = getMoneyRequestParticipantOptions({ + currentUserAccountID, + report: fakeReport, + policy: fakePolicy, + personalDetails: {}, + conciergeReportID: undefined, + privateIsArchived: undefined, + reportAttributesDerived: undefined, + reportDraft: undefined, + translate: translateLocal, + convertToDisplayString, + dateFnsLocale: undefined, + }); expect(Array.isArray(participants)).toBe(true); expect(participants.length).toBeGreaterThan(0); expect(participants.at(0)).toMatchObject({isDisabled: false}); }); it('should not mark participant as disabled when reportDrafts is undefined', () => { - const participants = getMoneyRequestParticipantOptions(currentUserAccountID, fakeReport, fakePolicy, {}, undefined, undefined, undefined, undefined, translateLocal, undefined); + const participants = getMoneyRequestParticipantOptions({ + currentUserAccountID, + report: fakeReport, + policy: fakePolicy, + personalDetails: {}, + conciergeReportID: undefined, + privateIsArchived: undefined, + reportAttributesDerived: undefined, + reportDraft: undefined, + translate: translateLocal, + convertToDisplayString, + dateFnsLocale: undefined, + }); expect(Array.isArray(participants)).toBe(true); expect(participants.length).toBeGreaterThan(0); // When reportDrafts is undefined, isDraftReport is called which checks Onyx directly diff --git a/tests/perf-test/OptionsListUtils.perf-test.ts b/tests/perf-test/OptionsListUtils.perf-test.ts index 7572cc653871..dbc8a7b7c711 100644 --- a/tests/perf-test/OptionsListUtils.perf-test.ts +++ b/tests/perf-test/OptionsListUtils.perf-test.ts @@ -22,7 +22,7 @@ import createRandomOptionData from '../utils/collections/optionData'; import createPersonalDetails from '../utils/collections/personalDetails'; import {getRandomDate} from '../utils/collections/reportActions'; import {createRandomReport} from '../utils/collections/reports'; -import {translateLocal} from '../utils/TestHelper'; +import {convertToDisplayString, translateLocal} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; const REPORTS_COUNT = 5000; @@ -105,6 +105,7 @@ const EMPTY_PRIVATE_IS_ARCHIVED_MAP: PrivateIsArchivedMap = {}; const CURRENT_USER_ACCOUNT_ID = 1; const options = createFilteredOptionList(personalDetails, reports, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, @@ -112,6 +113,7 @@ const options = createFilteredOptionList(personalDetails, reports, undefined, EM const ValidOptionsConfig = { dateFnsLocale: undefined, + convertToDisplayString, betas: mockedBetas, includeRecentReports: true, includeTasks: true, @@ -148,6 +150,7 @@ describe('OptionsListUtils', () => { await measureFunction(() => getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options, betas: mockedBetas, @@ -178,7 +181,10 @@ describe('OptionsListUtils', () => { translateLocal, ); await measureFunction(() => { - filterAndOrderOptions(formattedOptions, SEARCH_VALUE, COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, personalDetails); + filterAndOrderOptions(formattedOptions, SEARCH_VALUE, COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, personalDetails, { + dateFnsLocale: undefined, + convertToDisplayString, + }); }); }); test('[OptionsListUtils] getFilteredOptions with empty search value', async () => { @@ -195,7 +201,10 @@ describe('OptionsListUtils', () => { translateLocal, ); await measureFunction(() => { - filterAndOrderOptions(formattedOptions, '', COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, personalDetails); + filterAndOrderOptions(formattedOptions, '', COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, personalDetails, { + dateFnsLocale: undefined, + convertToDisplayString, + }); }); }); @@ -213,6 +222,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, betas: mockedBetas, includeMultipleParticipantReports: true, showChatPreviewLine: true, @@ -278,6 +288,7 @@ describe('OptionsListUtils', () => { MOCK_CURRENT_USER_ACCOUNT_ID, undefined, translateLocal, + convertToDisplayString, undefined, mockedPersonalDetails, true, @@ -292,7 +303,20 @@ describe('OptionsListUtils', () => { await waitForBatchedUpdates(); await measureFunction(() => - formatSectionsFromSearchTerm('', Object.values(selectedOptions), [], [], {}, MOCK_CURRENT_USER_ACCOUNT_ID, undefined, translateLocal, undefined, mockedPersonalDetails, true), + formatSectionsFromSearchTerm( + '', + Object.values(selectedOptions), + [], + [], + {}, + MOCK_CURRENT_USER_ACCOUNT_ID, + undefined, + translateLocal, + convertToDisplayString, + undefined, + mockedPersonalDetails, + true, + ), ); }); @@ -304,6 +328,7 @@ describe('OptionsListUtils', () => { return createFilteredOptionList(personalDetails, mockedReportsMap, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, maxRecentReports: 500, isSearching: false, @@ -317,6 +342,7 @@ describe('OptionsListUtils', () => { createFilteredOptionList(personalDetails, mockedReportsMap, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, maxRecentReports: 500, isSearching: true, @@ -333,6 +359,7 @@ describe('OptionsListUtils', () => { const largeOptionList = createFilteredOptionList(largePersonalDetails, largeReports, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: MOCK_CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); @@ -349,7 +376,10 @@ describe('OptionsListUtils', () => { ); await measureFunction(() => { - filterAndOrderOptions(formattedOptions, 'Email Report Five', COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, largePersonalDetails); + filterAndOrderOptions(formattedOptions, 'Email Report Five', COUNTRY_CODE, loginList, MOCK_CURRENT_USER_EMAIL, MOCK_CURRENT_USER_ACCOUNT_ID, largePersonalDetails, { + dateFnsLocale: undefined, + convertToDisplayString, + }); }); }); @@ -358,6 +388,7 @@ describe('OptionsListUtils', () => { const optionLists = createFilteredOptionList(personalDetails, mockedReportsMap, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, maxRecentReports: 500, isSearching: true, @@ -366,6 +397,7 @@ describe('OptionsListUtils', () => { await measureFunction(() => getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: optionLists, betas: mockedBetas, diff --git a/tests/perf-test/SidebarUtils.perf-test.ts b/tests/perf-test/SidebarUtils.perf-test.ts index b796d656a969..a5037b478301 100644 --- a/tests/perf-test/SidebarUtils.perf-test.ts +++ b/tests/perf-test/SidebarUtils.perf-test.ts @@ -16,7 +16,7 @@ import createPersonalDetails from '../utils/collections/personalDetails'; import createRandomPolicy from '../utils/collections/policies'; import createRandomReportAction, {getRandomDate} from '../utils/collections/reportActions'; import {createRandomReport} from '../utils/collections/reports'; -import {convertToDisplayString, localeCompare, translateLocal, formatPhoneNumber} from '../utils/TestHelper'; +import {convertToDisplayString, convertToDisplayStringWithoutCurrency, localeCompare, translateLocal, formatPhoneNumber} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; const REPORTS_COUNT = 15000; @@ -89,6 +89,7 @@ describe('SidebarUtils', () => { lastAction: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastActionReport: undefined, isReportArchived: undefined, diff --git a/tests/ui/RulesRequireReceiptsPageTest.tsx b/tests/ui/RulesRequireReceiptsPageTest.tsx index efd79ed3f8ba..af02a331ca70 100644 --- a/tests/ui/RulesRequireReceiptsPageTest.tsx +++ b/tests/ui/RulesRequireReceiptsPageTest.tsx @@ -8,7 +8,6 @@ import OnyxListItemProvider from '@components/OnyxListItemProvider'; import {CurrentReportIDContextProvider} from '@hooks/useCurrentReportID'; -import {convertToDisplayString} from '@libs/CurrencyUtils'; import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator'; import type {SettingsNavigatorParamList} from '@navigation/types'; @@ -76,11 +75,11 @@ const getSaveLabel = () => TestHelper.translateLocal('workspace.rules.requireRec /** The error shown on the receipt amount, naming the itemized amount it may not exceed. */ const getReceiptTooHighError = (itemizedAmountInCents: number) => - TestHelper.translateLocal('workspace.rules.individualExpenseRules.receiptRequiredAmountError', {amount: convertToDisplayString(itemizedAmountInCents, 'USD')}); + TestHelper.translateLocal('workspace.rules.individualExpenseRules.receiptRequiredAmountError', {amount: TestHelper.convertToDisplayString(itemizedAmountInCents, 'USD')}); /** The error shown on the itemized amount, naming the receipt amount it may not fall below. */ const getItemizedTooLowError = (receiptAmountInCents: number) => - TestHelper.translateLocal('workspace.rules.individualExpenseRules.itemizedReceiptRequiredAmountError', {amount: convertToDisplayString(receiptAmountInCents, 'USD')}); + TestHelper.translateLocal('workspace.rules.individualExpenseRules.itemizedReceiptRequiredAmountError', {amount: TestHelper.convertToDisplayString(receiptAmountInCents, 'USD')}); /** The single message shown below both amounts when they break their shared constraint. */ const getSharedAmountError = () => TestHelper.translateLocal('workspace.rules.requireReceipts.receiptAmountGreaterThanItemizedError'); diff --git a/tests/ui/SearchActionHeaderTest.tsx b/tests/ui/SearchActionHeaderTest.tsx index 42fd4e5babc0..8e5b690ac408 100644 --- a/tests/ui/SearchActionHeaderTest.tsx +++ b/tests/ui/SearchActionHeaderTest.tsx @@ -1,6 +1,7 @@ import {render, screen} from '@testing-library/react-native'; import ComposeProviders from '@components/ComposeProviders'; +import {CurrencyListContextProvider} from '@components/CurrencyListContextProvider'; import {LocaleContextProvider} from '@components/LocaleContextProvider'; import OnyxListItemProvider from '@components/OnyxListItemProvider'; import {SearchResultsContext} from '@components/Search/SearchContextDefinitions'; @@ -32,7 +33,7 @@ ThemeProviderWithLight.displayName = 'ThemeProviderWithLight'; function renderSearchActionHeader(action: ReportAction, report: Report | undefined, isOnSearch: boolean) { return render( - + {/* shouldUseLiveData: true keeps useOnyx reading from real Onyx collections instead of a search snapshot, since this test doesn't set up snapshot data */} (); const mockGetMerchant = jest.mocked(getMerchant); const mockGetDescription = jest.mocked(getDescription); const mockGetAmount = jest.mocked(getAmount); @@ -123,7 +121,7 @@ describe('AddExistingExpense Search Functionality', () => { // Add formatted amount to searchable fields const amount = getAmount(transaction); const currency = getCurrency(transaction); - const formattedAmount = convertToDisplayString(amount, currency); + const formattedAmount = mockConvertToDisplayString(amount, currency); searchableFields.push(formattedAmount); // This allows users to search "2000" and find "$2,000.00" for example diff --git a/tests/unit/CategoryContextualRulesUtilsTest.ts b/tests/unit/CategoryContextualRulesUtilsTest.ts index ddb67f4ef576..cefaba0f7a93 100644 --- a/tests/unit/CategoryContextualRulesUtilsTest.ts +++ b/tests/unit/CategoryContextualRulesUtilsTest.ts @@ -1,5 +1,4 @@ import getCategoryContextualRules from '@libs/CategoryContextualRulesUtils'; -import {convertToDisplayString} from '@libs/CurrencyUtils'; import CONST from '@src/CONST'; import IntlStore from '@src/languages/IntlStore'; @@ -7,7 +6,7 @@ import {DYNAMIC_ROUTES} from '@src/ROUTES'; import type {PolicyCategory} from '@src/types/onyx'; import createRandomPolicy from '../utils/collections/policies'; -import {translateLocal} from '../utils/TestHelper'; +import {convertToDisplayString, translateLocal} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; const policy = { diff --git a/tests/unit/CurrencyUtilsTest.ts b/tests/unit/CurrencyUtilsTest.ts index 56c47c2a8777..425e70f573ff 100644 --- a/tests/unit/CurrencyUtilsTest.ts +++ b/tests/unit/CurrencyUtilsTest.ts @@ -55,22 +55,6 @@ describe('CurrencyUtils', () => { ); }); - describe('getCurrencyDecimals', () => { - test('Currency decimals smaller than or equal 2', () => { - expect(CurrencyUtils.getCurrencyDecimals('JPY')).toBe(0); - expect(CurrencyUtils.getCurrencyDecimals('USD')).toBe(2); - expect(CurrencyUtils.getCurrencyDecimals('RSD')).toBe(2); - }); - - test('Currency decimals larger than 2 should return 2', () => { - // Actual: 3 - expect(CurrencyUtils.getCurrencyDecimals('LYD')).toBe(2); - - // Actual: 4 - expect(CurrencyUtils.getCurrencyDecimals('UYW')).toBe(2); - }); - }); - describe('convertToBackendAmount', () => { test.each([ [25, 2500], @@ -131,33 +115,6 @@ describe('CurrencyUtils', () => { }); }); - describe('convertToDisplayString', () => { - test.each([ - [CONST.CURRENCY.USD, 25, '$0.25'], - [CONST.CURRENCY.USD, 2500, '$25.00'], - [CONST.CURRENCY.USD, 150, '$1.50'], - [CONST.CURRENCY.USD, 250000, '$2,500.00'], - ['JPY', 2500, '¥25'], - ['JPY', 250000, '¥2,500'], - ['JPY', 2500.5, '¥25'], - ['RSD', 100, 'RSD\xa01.00'], - ['RSD', 145, 'RSD\xa01.45'], - ['BHD', 12345, 'BHD\xa0123.45'], - ['BHD', 1, 'BHD\xa00.01'], - ])('Correctly displays %s', (currency, amount, expectedResult) => { - expect(CurrencyUtils.convertToDisplayString(amount, currency)).toBe(expectedResult); - }); - - test.each([ - ['EUR', 25, '0,25\xa0€'], - ['EUR', 2500, '25,00\xa0€'], - ['EUR', 250000, '2500,00\xa0€'], - ['EUR', 250000000, '2.500.000,00\xa0€'], - ])('Correctly displays %s in ES locale', (currency, amount, expectedResult) => - IntlStore.load(CONST.LOCALES.ES).then(() => expect(CurrencyUtils.convertToDisplayString(amount, currency)).toBe(expectedResult)), - ); - }); - describe('convertToShortDisplayString', () => { test.each([ [CONST.CURRENCY.USD, 25, '$0'], @@ -263,7 +220,7 @@ describe('CurrencyUtils', () => { test('shares the throttle across helpers that go through sanitizeCurrencyCode', () => { const warnSpy = jest.spyOn(Log, 'warn').mockImplementation(() => undefined); try { - CurrencyUtils.convertToDisplayString(2500, 'XX'); + CurrencyUtils.convertAmountToDisplayString(2500, 'XX'); CurrencyUtils.getLocalizedCurrencySymbol(CONST.LOCALES.EN, 'XX'); CurrencyUtils.convertToShortDisplayString(2500, 'XX'); expect(warnSpy).toHaveBeenCalledTimes(1); @@ -273,27 +230,6 @@ describe('CurrencyUtils', () => { }); }); - describe('convertToDisplayString with malformed currency', () => { - test.each(['', 'XX', 'USDD', '???'])('does not throw and falls back to USD formatting for %p', (input) => { - expect(() => CurrencyUtils.convertToDisplayString(2500, input)).not.toThrow(); - expect(CurrencyUtils.convertToDisplayString(2500, input)).toBe('$25.00'); - }); - - test('normalizes case-only variations to the intended currency instead of USD', () => { - expect(CurrencyUtils.convertToDisplayString(2500, 'eur')).toBe(CurrencyUtils.convertToDisplayString(2500, 'EUR')); - }); - - test('falls back to USD when shouldUseLocalCurrencySymbol is true and currency is malformed', () => { - expect(() => CurrencyUtils.convertToDisplayString(2500, 'invalid', true)).not.toThrow(); - // USD has a known local symbol in the currencyList, so the local-symbol branch should produce a $-prefixed result. - expect(CurrencyUtils.convertToDisplayString(2500, 'invalid', true)).toMatch(/\$/); - }); - - test('handles undefined currency via the default parameter', () => { - expect(CurrencyUtils.convertToDisplayString(2500, undefined)).toBe('$25.00'); - }); - }); - describe('convertToShortDisplayString with malformed currency', () => { test.each(['', 'XX', 'USDD', '???'])('does not throw and falls back to USD formatting for %p', (input) => { expect(() => CurrencyUtils.convertToShortDisplayString(2500, input)).not.toThrow(); @@ -309,29 +245,6 @@ describe('CurrencyUtils', () => { }); }); - describe('convertToDisplayStringWithoutCurrency with malformed currency', () => { - test.each(['', 'XX', 'USDD', '???'])('does not throw and produces a numeric output for %p', (input) => { - expect(() => CurrencyUtils.convertToDisplayStringWithoutCurrency(2500, input)).not.toThrow(); - // Output should not contain a currency symbol but should contain the numeric portion. - const result = CurrencyUtils.convertToDisplayStringWithoutCurrency(2500, input); - expect(result).not.toMatch(/\$/); - expect(result).toContain('25'); - }); - }); - - describe('convertToDisplayStringWithExplicitCurrency with malformed currency', () => { - test.each(['XX', 'USDD', '???'])('does not throw and falls back to USD formatting for truthy malformed %p', (input) => { - expect(() => CurrencyUtils.convertToDisplayStringWithExplicitCurrency(2500, input)).not.toThrow(); - expect(CurrencyUtils.convertToDisplayStringWithExplicitCurrency(2500, input)).toBe('$25.00'); - }); - - test.each([undefined, ''])('returns the symbol-less form for falsy currency %p (delegates to convertToDisplayStringWithoutCurrency)', (input) => { - const result = CurrencyUtils.convertToDisplayStringWithExplicitCurrency(2500, input); - expect(result).not.toMatch(/\$/); - expect(result).toContain('25'); - }); - }); - describe('getLocalizedCurrencySymbol with malformed currency', () => { test.each(['', 'XX', 'USDD'])('returns the USD symbol without throwing for %p', (input) => { expect(() => CurrencyUtils.getLocalizedCurrencySymbol(CONST.LOCALES.EN, input)).not.toThrow(); diff --git a/tests/unit/IOUAmountSubmissionTest.ts b/tests/unit/IOUAmountSubmissionTest.ts index e250621c1290..408a946ef7ab 100644 --- a/tests/unit/IOUAmountSubmissionTest.ts +++ b/tests/unit/IOUAmountSubmissionTest.ts @@ -12,7 +12,7 @@ import Onyx from 'react-native-onyx'; import createRandomPolicy from '../utils/collections/policies'; import {createRandomReport} from '../utils/collections/reports'; -import {formatPhoneNumber, getCurrencyDecimalsLocal, getCurrencySymbolLocal, translateLocal} from '../utils/TestHelper'; +import {convertToDisplayString, formatPhoneNumber, getCurrencyDecimalsLocal, getCurrencySymbolLocal, translateLocal} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; const CURRENT_USER_ACCOUNT_ID = 5; @@ -171,6 +171,7 @@ describe('AmountSubmission', () => { report: baseReport, translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, getCurrencyDecimals: getCurrencyDecimalsLocal, getCurrencySymbol: getCurrencySymbolLocal, transaction: undefined, diff --git a/tests/unit/MoneyRequestReportButtonUtils.test.ts b/tests/unit/MoneyRequestReportButtonUtils.test.ts index ec68b0614cd4..c5d6b4423c8e 100644 --- a/tests/unit/MoneyRequestReportButtonUtils.test.ts +++ b/tests/unit/MoneyRequestReportButtonUtils.test.ts @@ -1,4 +1,3 @@ -import {convertToDisplayString} from '@libs/CurrencyUtils'; import {getTotalAmountForIOUReportPreviewButton} from '@libs/MoneyRequestReportUtils'; import {hasOnlyNonReimbursableTransactions} from '@libs/ReportUtils'; @@ -30,9 +29,7 @@ jest.mock('@libs/ReportUtils', () => ({ }), })); -jest.mock('@libs/CurrencyUtils', () => ({ - convertToDisplayString: jest.fn().mockImplementation((amountInCents = 0): string => `$${amountInCents}.00`), -})); +const convertToDisplayString = jest.fn().mockImplementation((amountInCents: number | undefined = 0): string => `$${amountInCents}.00`); describe('ReportButtonUtils', () => { describe('getTotalAmountForIOUReportPreviewButton', () => { diff --git a/tests/unit/OnyxDerivedTest.tsx b/tests/unit/OnyxDerivedTest.tsx index 059f5ef85cfc..f5fe01e62db3 100644 --- a/tests/unit/OnyxDerivedTest.tsx +++ b/tests/unit/OnyxDerivedTest.tsx @@ -192,11 +192,11 @@ describe('OnyxDerived', () => { // When the report attributes are recomputed with both report and transaction updates reportAttributes.compute( - [reports, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined], + [reports, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined], {}, ); const reportAttributesComputedValue = reportAttributes.compute( - [reports, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined], + [reports, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined], { sourceValues: { [ONYXKEYS.COLLECTION.REPORT]: { @@ -310,17 +310,33 @@ describe('OnyxDerived', () => { // Reset the module-level diff baseline (no sourceValues clears it) so the seed below is deterministic. reportAttributes.compute( - [reports, undefined, undefined, undefined, undefined, undefined, personalDetails, undefined, undefined, undefined, undefined, undefined, undefined, undefined], + [reports, undefined, undefined, undefined, undefined, undefined, personalDetails, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined], {}, ); // First personal-details compute computes both reports (no prior currentValue) and seeds the baseline. const initial = reportAttributes.compute( - [reports, undefined, undefined, undefined, undefined, undefined, personalDetails, undefined, undefined, undefined, undefined, undefined, undefined, undefined], + [reports, undefined, undefined, undefined, undefined, undefined, personalDetails, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined], personalDetailsSource, ); // Changing only account 2's display name should recompute just its report, carrying the other by reference. const afterChange = reportAttributes.compute( - [reports, undefined, undefined, undefined, undefined, undefined, changedPersonalDetails, undefined, undefined, undefined, undefined, undefined, undefined, undefined], + [ + reports, + undefined, + undefined, + undefined, + undefined, + undefined, + changedPersonalDetails, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + ], {...personalDetailsSource, currentValue: initial}, ); diff --git a/tests/unit/OptionsListUtilsTest.tsx b/tests/unit/OptionsListUtilsTest.tsx index 1b8d9bc12f22..77dd26b2f0ea 100644 --- a/tests/unit/OptionsListUtilsTest.tsx +++ b/tests/unit/OptionsListUtilsTest.tsx @@ -66,7 +66,7 @@ import Onyx from 'react-native-onyx'; import createRandomReportAction from '../utils/collections/reportActions'; import {createRandomReport, createRegularChat} from '../utils/collections/reports'; import {getFakeAdvancedReportAction} from '../utils/LHNTestUtils'; -import {convertToDisplayString, formatPhoneNumber, localeCompare, translateLocal} from '../utils/TestHelper'; +import {convertToDisplayString, convertToDisplayStringWithoutCurrency, formatPhoneNumber, localeCompare, translateLocal} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; jest.mock('@rnmapbox/maps', () => { @@ -796,6 +796,7 @@ describe('OptionsListUtils', () => { OPTIONS = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, MOCK_REPORT_ATTRIBUTES_DERIVED, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -805,7 +806,7 @@ describe('OptionsListUtils', () => { MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_CONCIERGE, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, - {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, conciergeReportID: undefined, isSearching: true}, + {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, convertToDisplayString, conciergeReportID: undefined, isSearching: true}, ); OPTIONS_WITH_CHRONOS = createFilteredOptionList( PERSONAL_DETAILS_WITH_CHRONOS, @@ -813,7 +814,7 @@ describe('OptionsListUtils', () => { MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_CHRONOS, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, - {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, conciergeReportID: undefined, isSearching: true}, + {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, convertToDisplayString, conciergeReportID: undefined, isSearching: true}, ); OPTIONS_WITH_RECEIPTS = createFilteredOptionList( PERSONAL_DETAILS_WITH_RECEIPTS, @@ -821,7 +822,7 @@ describe('OptionsListUtils', () => { MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_RECEIPTS, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, - {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, conciergeReportID: undefined, isSearching: true}, + {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, convertToDisplayString, conciergeReportID: undefined, isSearching: true}, ); OPTIONS_WITH_WORKSPACE_ROOM = createFilteredOptionList( PERSONAL_DETAILS, @@ -829,7 +830,7 @@ describe('OptionsListUtils', () => { MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_WORKSPACE_ROOM, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, - {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, conciergeReportID: undefined, isSearching: true}, + {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, convertToDisplayString, conciergeReportID: undefined, isSearching: true}, ); }); @@ -855,6 +856,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with all betas const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -905,12 +907,13 @@ describe('OptionsListUtils', () => { createMockReportAttributesDerived(memberWorkspaceChat, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID), EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, - {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, conciergeReportID: undefined, isSearching: true}, + {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, convertToDisplayString, conciergeReportID: undefined, isSearching: true}, ); // When we call getSearchOptions const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: optionsWithMemberWorkspaceChat, reportAttributesDerived: createMockReportAttributesDerived(memberWorkspaceChat, PERSONAL_DETAILS, CURRENT_USER_ACCOUNT_ID), @@ -934,6 +937,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with includeCurrentUser set to true const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, draftComments: {}, @@ -969,6 +973,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with includeCurrentUser set to false (default behavior) const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, draftComments: {}, @@ -1001,6 +1006,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with policyCollection const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_WORKSPACE_ROOM, draftComments: {}, @@ -1033,6 +1039,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with empty policyCollection const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, draftComments: {}, @@ -1064,6 +1071,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with undefined policyCollection const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, draftComments: {}, @@ -1096,6 +1104,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with conciergeReportID const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_CONCIERGE, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_CONCIERGE, @@ -1122,6 +1131,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with conciergeReportID set to undefined const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_CONCIERGE, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_CONCIERGE, @@ -1150,6 +1160,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with a search query matching Concierge const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_CONCIERGE, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_CONCIERGE, @@ -1187,7 +1198,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); let results: Pick = validOptions; @@ -1229,7 +1240,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); let results: Pick = validOptions; @@ -1267,7 +1278,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); @@ -1294,7 +1305,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); @@ -1336,6 +1347,7 @@ describe('OptionsListUtils', () => { const optionList = createFilteredOptionList(personalDetails, {}, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -1350,6 +1362,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, includeRecentReports: false, personalDetails, searchString, @@ -1360,7 +1373,10 @@ describe('OptionsListUtils', () => { // The contact must survive getValidOptions' pre-filter so the final filter can return it. expect(preFilteredOptions.personalDetails).toEqual(expect.arrayContaining([expect.objectContaining({login: 'contact1003@example.com'})])); - const filteredOptions = filterAndOrderOptions(preFilteredOptions, searchString, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, personalDetails); + const filteredOptions = filterAndOrderOptions(preFilteredOptions, searchString, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, personalDetails, { + dateFnsLocale: undefined, + convertToDisplayString, + }); expect(filteredOptions.personalDetails).toEqual([expect.objectContaining({login: 'contact1003@example.com'})]); }); @@ -1379,7 +1395,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, sortedActions: undefined}, translateLocal, ); @@ -1404,7 +1420,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, conciergeReportID, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); @@ -1429,7 +1445,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, sortedActions: undefined}, translateLocal, ); @@ -1453,7 +1469,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, sortedActions: undefined}, translateLocal, ); @@ -1506,7 +1522,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeMultipleParticipantReports: true, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, includeMultipleParticipantReports: true, sortedActions: undefined}, translateLocal, ); const adminRoomOption = results.recentReports.find((report) => report.reportID === '1455140530846319'); @@ -1559,7 +1575,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeMultipleParticipantReports: true, showRBR: true, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, includeMultipleParticipantReports: true, showRBR: true, sortedActions: undefined}, translateLocal, ); expect(results.recentReports.at(0)?.brickRoadIndicator).toBe(CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR); @@ -1609,7 +1625,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeMultipleParticipantReports: true, showRBR: false, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, includeMultipleParticipantReports: true, showRBR: false, sortedActions: undefined}, translateLocal, ); expect(results.recentReports.at(0)?.brickRoadIndicator).toBe(null); @@ -1663,7 +1679,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeRecentReports: true, shouldUnreadBeBold: true, includeMultipleParticipantReports: true, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, includeRecentReports: true, shouldUnreadBeBold: true, includeMultipleParticipantReports: true, sortedActions: undefined}, translateLocal, ); @@ -1695,7 +1711,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, personalDetails: customPersonalDetails, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, personalDetails: customPersonalDetails, sortedActions: undefined}, translateLocal, ); @@ -1718,7 +1734,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, selectedOptions, includeSelectedOptions: true, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, selectedOptions, includeSelectedOptions: true, sortedActions: undefined}, translateLocal, ); @@ -1741,7 +1757,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, maxElements: 1}, + {dateFnsLocale: undefined, convertToDisplayString, maxElements: 1}, translateLocal, ); @@ -1757,7 +1773,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, maxElements: 100}, + {dateFnsLocale: undefined, convertToDisplayString, maxElements: 100}, translateLocal, ); @@ -1781,6 +1797,7 @@ describe('OptionsListUtils', () => { const lazyList = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, MOCK_REPORT_ATTRIBUTES_DERIVED, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -1803,7 +1820,7 @@ describe('OptionsListUtils', () => { const {eagerList, lazyList} = buildOptionLists(); // When both lists go through getValidOptions with a top-N cap that exercises the heap - const config = {dateFnsLocale: undefined, maxElements: 3, personalDetails: PERSONAL_DETAILS}; + const config = {dateFnsLocale: undefined, convertToDisplayString, maxElements: 3, personalDetails: PERSONAL_DETAILS}; const {options: eagerResults} = getValidOptions(eagerList, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); const {options: lazyResults} = getValidOptions(lazyList, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); @@ -1819,7 +1836,7 @@ describe('OptionsListUtils', () => { const {eagerList, lazyList} = buildOptionLists(); // When both lists go through getValidOptions with a search string (contact filtering reads text/login/participantsList) - const config = {dateFnsLocale: undefined, searchString: 'spider', personalDetails: PERSONAL_DETAILS}; + const config = {dateFnsLocale: undefined, convertToDisplayString, searchString: 'spider', personalDetails: PERSONAL_DETAILS}; const {options: eagerResults} = getValidOptions(eagerList, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); const {options: lazyResults} = getValidOptions(lazyList, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); @@ -1886,10 +1903,13 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, searchString, includeP2P: true}, + {dateFnsLocale: undefined, convertToDisplayString, searchString, includeP2P: true}, translateLocal, ); - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then the report must survive both filtering stages expect(filteredOptions.recentReports).toEqual(expect.arrayContaining([expect.objectContaining({reportID: report.reportID, text: reportText})])); @@ -1951,7 +1971,7 @@ describe('OptionsListUtils', () => { const {eagerList, lazyList} = buildOptionLists(); // When both lists go through getValidOptions with a custom exclusion (filter reads shell.login) - const config = {dateFnsLocale: undefined, excludeLogins: {'peterparker@expensify.com': true}, personalDetails: PERSONAL_DETAILS}; + const config = {dateFnsLocale: undefined, convertToDisplayString, excludeLogins: {'peterparker@expensify.com': true}, personalDetails: PERSONAL_DETAILS}; const {options: eagerResults} = getValidOptions(eagerList, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); const {options: lazyResults} = getValidOptions(lazyList, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); @@ -1965,6 +1985,7 @@ describe('OptionsListUtils', () => { const lazyList = createFilteredOptionList({}, REPORTS, MOCK_REPORT_ATTRIBUTES_DERIVED, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -1978,7 +1999,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); @@ -2002,6 +2023,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, personalDetails: PERSONAL_DETAILS, }, translateLocal, @@ -2027,7 +2049,7 @@ describe('OptionsListUtils', () => { // When both lists go through getValidOptions with search + maxElements together // (filter selects matches, then the heap keeps only the top-N survivors to hydrate) - const config = {dateFnsLocale: undefined, searchString: 'man', maxElements: 3, personalDetails: PERSONAL_DETAILS}; + const config = {dateFnsLocale: undefined, convertToDisplayString, searchString: 'man', maxElements: 3, personalDetails: PERSONAL_DETAILS}; const {options: eagerResults} = getValidOptions(eagerList, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); const {options: lazyResults} = getValidOptions(lazyList, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); @@ -2044,11 +2066,13 @@ describe('OptionsListUtils', () => { const firstLazyList = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, MOCK_REPORT_ATTRIBUTES_DERIVED, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); const cachedLazyList = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, MOCK_REPORT_ATTRIBUTES_DERIVED, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); const eagerList = hydrateAllPersonalDetails(firstLazyList); @@ -2069,7 +2093,7 @@ describe('OptionsListUtils', () => { } // When both the fresh and cached lazy lists go through getValidOptions - const config = {dateFnsLocale: undefined, maxElements: 3, personalDetails: PERSONAL_DETAILS}; + const config = {dateFnsLocale: undefined, convertToDisplayString, maxElements: 3, personalDetails: PERSONAL_DETAILS}; const {options: firstResults} = getValidOptions(firstLazyList, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); const {options: cachedResults} = getValidOptions(cachedLazyList, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); const {options: eagerResults} = getValidOptions(eagerList, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); @@ -2085,6 +2109,7 @@ describe('OptionsListUtils', () => { const options = { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, maxRecentReports, includeP2P, @@ -2123,6 +2148,7 @@ describe('OptionsListUtils', () => { const lazyList = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, attributesWithError, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -2213,7 +2239,7 @@ describe('OptionsListUtils', () => { }; // When both mixed lists are filtered for the device contact - const config = {dateFnsLocale: undefined, searchString: 'Device Contact Jane', personalDetails: PERSONAL_DETAILS}; + const config = {dateFnsLocale: undefined, convertToDisplayString, searchString: 'Device Contact Jane', personalDetails: PERSONAL_DETAILS}; const {options: eagerResults} = getValidOptions(eagerWithContacts, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); const {options: lazyResults} = getValidOptions(lazyWithContacts, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); @@ -2276,6 +2302,7 @@ describe('OptionsListUtils', () => { const list = createFilteredOptionList(PARITY_PERSONAL_DETAILS, PARITY_REPORTS, PARITY_ATTRIBUTES, PARITY_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -2303,6 +2330,7 @@ describe('OptionsListUtils', () => { item: PARITY_PERSONAL_DETAIL, ...createOption({ dateFnsLocale: undefined, + convertToDisplayString, accountIDs: [PARITY_ACCOUNT_ID], personalDetails: PARITY_PERSONAL_DETAILS, report: PARITY_REPORT, @@ -2348,6 +2376,7 @@ describe('OptionsListUtils', () => { const list = createFilteredOptionList(PARITY_PERSONAL_DETAILS, PARITY_REPORTS, PARITY_ATTRIBUTES, PARITY_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: PARITY_REPORT_ID, isSearching: true, }); @@ -2362,6 +2391,7 @@ describe('OptionsListUtils', () => { const hydrated = hydrateContactOption(shell); const withConcierge = createOption({ dateFnsLocale: undefined, + convertToDisplayString, accountIDs: [PARITY_ACCOUNT_ID], personalDetails: PARITY_PERSONAL_DETAILS, report: PARITY_REPORT, @@ -2390,18 +2420,20 @@ describe('OptionsListUtils', () => { const first = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, MOCK_REPORT_ATTRIBUTES_DERIVED, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); const second = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, MOCK_REPORT_ATTRIBUTES_DERIVED, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); expect(first.personalDetails.length).toBeGreaterThan(0); expect(second.personalDetails.length).toBe(first.personalDetails.length); // When both are run through getValidOptions (the first pass builds, the second must not) - const config = {dateFnsLocale: undefined, personalDetails: PERSONAL_DETAILS}; + const config = {dateFnsLocale: undefined, convertToDisplayString, personalDetails: PERSONAL_DETAILS}; const firstBuilds = first.personalDetails.map(buildIdentity); const {options: firstResults} = getValidOptions(first, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); const {options: secondResults} = getValidOptions(second, allPolicies, {}, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, config, translateLocal); @@ -2426,6 +2458,7 @@ describe('OptionsListUtils', () => { const list = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, MOCK_REPORT_ATTRIBUTES_DERIVED, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -2465,6 +2498,7 @@ describe('OptionsListUtils', () => { const list = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, MOCK_REPORT_ATTRIBUTES_DERIVED, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -2500,7 +2534,15 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, includeOwnedWorkspaceChats: true, sortedActions: undefined}, + { + dateFnsLocale: undefined, + convertToDisplayString, + includeRecentReports: true, + includeMultipleParticipantReports: true, + includeP2P: true, + includeOwnedWorkspaceChats: true, + sortedActions: undefined, + }, translateLocal, ); @@ -2539,6 +2581,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, @@ -2569,6 +2612,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, @@ -2598,6 +2642,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, @@ -2627,6 +2672,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, includeRecentReports: true, includeMultipleParticipantReports: true, includeP2P: true, @@ -2656,7 +2702,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); const reportLogins = new Set(results.recentReports.map((reportOption) => reportOption.login)); @@ -2679,7 +2725,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, excludeLogins: {'peterparker@expensify.com': true}, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, excludeLogins: {'peterparker@expensify.com': true}, sortedActions: undefined}, translateLocal, ); @@ -2702,7 +2748,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); @@ -2726,7 +2772,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, excludeLogins: {[CONST.EMAIL.CONCIERGE]: true}, sortedActions: undefined}, translateLocal, ); @@ -2751,7 +2797,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, excludeLogins: {[CONST.EMAIL.CHRONOS]: true}, sortedActions: undefined}, translateLocal, ); @@ -2776,7 +2822,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, excludeLogins: {[CONST.EMAIL.RECEIPTS]: true}, sortedActions: undefined}, translateLocal, ); @@ -2799,7 +2845,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, maxRecentReportElements: maxRecentReports, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, maxRecentReportElements: maxRecentReports, sortedActions: undefined}, translateLocal, ); @@ -2818,7 +2864,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); const {options: resultsWithLimit} = getValidOptions( @@ -2829,7 +2875,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, maxRecentReportElements: 2, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, maxRecentReportElements: 2, sortedActions: undefined}, translateLocal, ); @@ -2848,7 +2894,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); const {options: resultsWithLimit} = getValidOptions( @@ -2859,7 +2905,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, maxRecentReportElements: 2, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, maxRecentReportElements: 2, sortedActions: undefined}, translateLocal, ); @@ -2880,7 +2926,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, maxElements: maxTotalElements, maxRecentReportElements: maxRecentReports, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, maxElements: maxTotalElements, maxRecentReportElements: maxRecentReports, sortedActions: undefined}, translateLocal, ); @@ -2919,6 +2965,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, betas: [], includeMultipleParticipantReports: true, showChatPreviewLine: true, @@ -2966,6 +3013,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, betas: [], includeMultipleParticipantReports: true, showChatPreviewLine: true, @@ -3014,6 +3062,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with all betas const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -3028,7 +3077,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we pass the returned options to filterAndOrderOptions with an empty search value - const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then all options should be returned expect(filteredOptions.recentReports.length + filteredOptions.personalDetails.length).toBe(14); @@ -3040,6 +3092,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with all betas const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -3056,6 +3109,7 @@ describe('OptionsListUtils', () => { // When we pass the returned options to filterAndOrderOptions with a search value and sortByReportTypeInSearch param const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { dateFnsLocale: undefined, + convertToDisplayString, sortByReportTypeInSearch: true, }); @@ -3076,6 +3130,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with all betas const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -3090,7 +3145,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -3107,12 +3165,14 @@ describe('OptionsListUtils', () => { const OPTIONS_WITH_ARCHIVED = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, MOCK_REPORT_ATTRIBUTES_DERIVED, archivedMap, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); // When we call getSearchOptions with all betas const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_ARCHIVED, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -3127,7 +3187,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -3142,12 +3205,14 @@ describe('OptionsListUtils', () => { const OPTIONS_WITH_PERIODS = createFilteredOptionList(PERSONAL_DETAILS_WITH_PERIODS, REPORTS, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); // When we call getSearchOptions with all betas const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_PERIODS, draftComments: {}, @@ -3163,6 +3228,7 @@ describe('OptionsListUtils', () => { // When we pass the returned options to filterAndOrderOptions with a search value and sortByReportTypeInSearch param const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS_WITH_PERIODS, { dateFnsLocale: undefined, + convertToDisplayString, sortByReportTypeInSearch: true, }); @@ -3178,6 +3244,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with all betas const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_WORKSPACE_ROOM, draftComments: {}, @@ -3191,7 +3258,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -3204,6 +3274,7 @@ describe('OptionsListUtils', () => { // Given a set of options with all betas const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -3218,7 +3289,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then only one report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -3236,11 +3310,12 @@ describe('OptionsListUtils', () => { MOCK_REPORT_ATTRIBUTES_DERIVED_WITH_CHAT_ROOM, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, - {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, conciergeReportID: undefined, isSearching: true}, + {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, convertToDisplayString, conciergeReportID: undefined, isSearching: true}, ); // When we call getSearchOptions with all betas const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_CHAT_ROOMS, draftComments: {}, @@ -3254,7 +3329,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we pass the returned options to filterAndOrderOptions with a search value - const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then only two reports should be returned expect(filterOptions.recentReports.length).toBe(2); @@ -3268,6 +3346,7 @@ describe('OptionsListUtils', () => { // Given a set of options const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -3281,7 +3360,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then only three reports should be returned expect(filteredOptions.recentReports.length).toBe(3); @@ -3296,6 +3378,7 @@ describe('OptionsListUtils', () => { // Given a set of options const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -3310,7 +3393,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then the user to invite should be returned expect(filteredOptions.userToInvite?.login).toBe(searchText); @@ -3327,12 +3413,13 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, sortedActions: undefined}, translateLocal, ); // When we call filterAndOrderOptions with a search value and excluded logins list const filterOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { dateFnsLocale: undefined, + convertToDisplayString, excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, }); @@ -3345,6 +3432,7 @@ describe('OptionsListUtils', () => { // Given a set of options const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -3361,6 +3449,7 @@ describe('OptionsListUtils', () => { // When we call filterAndOrderOptions with a search value and excludeLogins const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { dateFnsLocale: undefined, + convertToDisplayString, excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, }); @@ -3373,6 +3462,7 @@ describe('OptionsListUtils', () => { // Given a set of options const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -3389,6 +3479,7 @@ describe('OptionsListUtils', () => { // When we call filterAndOrderOptions with a search value and maxRecentReportsToShow set to 2 const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { dateFnsLocale: undefined, + convertToDisplayString, maxRecentReportsToShow: 2, }); @@ -3399,6 +3490,7 @@ describe('OptionsListUtils', () => { // When we call filterAndOrderOptions with a search value and maxRecentReportsToShow set to 0 const limitToZeroOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { dateFnsLocale: undefined, + convertToDisplayString, maxRecentReportsToShow: 0, }); @@ -3411,6 +3503,7 @@ describe('OptionsListUtils', () => { // Given a set of options with all betas const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -3425,7 +3518,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchText, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then there should be one matching result expect(filteredOptions.personalDetails.length).toBe(1); @@ -3453,6 +3549,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, betas: [], includeMultipleParticipantReports: true, showChatPreviewLine: true, @@ -3470,7 +3567,10 @@ describe('OptionsListUtils', () => { translateLocal, ); // When we pass the returned options to filterAndOrderOptions with a search value that does not match the group chat name - const filteredOptions = filterAndOrderOptions(options, 'mutants', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'mutants', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3501,6 +3601,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, betas: [], includeMultipleParticipantReports: true, showChatPreviewLine: true, @@ -3518,7 +3619,10 @@ describe('OptionsListUtils', () => { translateLocal, ); // When we pass the returned options to filterAndOrderOptions with a search value that matches the group chat name - const filteredOptions = filterAndOrderOptions(options, 'Avengers Room', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'Avengers Room', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then one recent report should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -3549,6 +3653,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, betas: [], includeMultipleParticipantReports: true, showChatPreviewLine: true, @@ -3566,7 +3671,10 @@ describe('OptionsListUtils', () => { translateLocal, ); // When we pass the returned options to filterAndOrderOptions with a search value that does not match the group chat name - const filteredOptions = filterAndOrderOptions(options, 'Mutants Lair', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'Mutants Lair', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3582,11 +3690,14 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with a search value that matches a personal detail with no existing report - const filteredOptions = filterAndOrderOptions(options, 'hulk', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'hulk', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3624,6 +3735,7 @@ describe('OptionsListUtils', () => { const OPTIONS_WITH_GROUP_CHAT = createFilteredOptionList(PERSONAL_DETAILS, REPORTS_WITH_GROUP_CHAT, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -3631,6 +3743,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with a search query that matches a participant display name const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_GROUP_CHAT, draftComments: {}, @@ -3679,6 +3792,7 @@ describe('OptionsListUtils', () => { const OPTIONS_WITH_GROUP_CHAT = createFilteredOptionList(PERSONAL_DETAILS, REPORTS_WITH_GROUP_CHAT, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -3686,6 +3800,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with a search query that matches a participant login const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_GROUP_CHAT, draftComments: {}, @@ -3734,6 +3849,7 @@ describe('OptionsListUtils', () => { const OPTIONS_WITH_GROUP_CHAT = createFilteredOptionList(PERSONAL_DETAILS, REPORTS_WITH_GROUP_CHAT, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -3741,6 +3857,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with a search query that matches a participant name const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_GROUP_CHAT, draftComments: {}, @@ -3789,6 +3906,7 @@ describe('OptionsListUtils', () => { const OPTIONS_WITH_GROUP_CHAT = createFilteredOptionList(PERSONAL_DETAILS, REPORTS_WITH_GROUP_CHAT, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -3796,6 +3914,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with a search query that does not match any participant const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_GROUP_CHAT, draftComments: {}, @@ -3842,12 +3961,13 @@ describe('OptionsListUtils', () => { undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, - {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, conciergeReportID: undefined, isSearching: true}, + {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, convertToDisplayString, conciergeReportID: undefined, isSearching: true}, ); // When we call getSearchOptions with all betas const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_GROUP_CHAT_NO_PARTICIPANTS, draftComments: {}, @@ -3862,7 +3982,10 @@ describe('OptionsListUtils', () => { }); // When we pass the returned options to filterAndOrderOptions with any search value - const filteredOptions = filterAndOrderOptions(options, 'Unknown', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'Unknown', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then the report should still be found by its reportName even if participantsList is empty expect(filteredOptions.recentReports.length).toBe(1); @@ -3879,11 +4002,14 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports - const filteredOptions = filterAndOrderOptions(options, 'marc@expensify', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'marc@expensify', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3902,11 +4028,14 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports - const filteredOptions = filterAndOrderOptions(options, 'marc@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'marc@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3925,11 +4054,14 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, 'peter.parker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'peter.parker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then no recent reports should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3947,11 +4079,14 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with a search value without accent mark - const filteredOptions = filterAndOrderOptions(options, 'Timothee', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'Timothee', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then one personalDetails with accent mark should be returned expect(filteredOptions.personalDetails.length).toBe(1); @@ -3967,11 +4102,14 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, '5005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, '5005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -3992,11 +4130,14 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, '+15005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, '+15005550006', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -4017,11 +4158,14 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports but matches user to invite - const filteredOptions = filterAndOrderOptions(options, '+1 (800)324-3233', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, '+1 (800)324-3233', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -4042,11 +4186,14 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with a search value that does not match any personal details or reports - const filteredOptions = filterAndOrderOptions(options, '998243aaaa', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, '998243aaaa', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then no recent reports or personal details should be returned expect(filteredOptions.recentReports.length).toBe(0); @@ -4065,13 +4212,14 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeUserToInvite: true, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, includeUserToInvite: true, sortedActions: undefined}, translateLocal, ); // When we call filterAndOrderOptions with a plain text name (not email or phone) without shouldAcceptName const filteredOptions = filterAndOrderOptions(options, 'Jeff Amazon', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { dateFnsLocale: undefined, + convertToDisplayString, shouldAcceptName: false, }); @@ -4089,13 +4237,14 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeUserToInvite: true, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, includeUserToInvite: true, sortedActions: undefined}, translateLocal, ); // When we call filterAndOrderOptions with a plain text name (not email or phone) with shouldAcceptName const filteredOptions = filterAndOrderOptions(options, 'Jeff', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { dateFnsLocale: undefined, + convertToDisplayString, shouldAcceptName: true, }); @@ -4113,11 +4262,14 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with a search value that does not match any personal details - const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'magneto', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then no personal details should be returned expect(filteredOptions.personalDetails.length).toBe(0); @@ -4133,12 +4285,13 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with a search value that matches an email const filteredOptions = filterAndOrderOptions(options, 'peterparker@expensify.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { dateFnsLocale: undefined, + convertToDisplayString, sortByReportTypeInSearch: true, }); @@ -4160,12 +4313,13 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with a search value that matches both reports and personal details and maxRecentReportsToShow param const filteredOptions = filterAndOrderOptions(options, '.com', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { dateFnsLocale: undefined, + convertToDisplayString, maxRecentReportsToShow: 5, }); @@ -4184,6 +4338,7 @@ describe('OptionsListUtils', () => { // Given a set of options const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -4197,7 +4352,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we call filterAndOrderOptions with a search value that matches a personal detail - const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then one personal detail should be returned expect(filteredOptions.recentReports.length).toBe(1); @@ -4209,6 +4367,7 @@ describe('OptionsListUtils', () => { // Given a set of options const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -4222,7 +4381,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we call filterAndOrderOptions with a search value that matches multiple items - const filteredOptions = filterAndOrderOptions(options, 'fantastic', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'fantastic', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then only three reports should be returned expect(filteredOptions.recentReports.length).toBe(3); @@ -4238,12 +4400,14 @@ describe('OptionsListUtils', () => { const OPTIONS_WITH_PERIODS = createFilteredOptionList(PERSONAL_DETAILS_WITH_PERIODS, REPORTS, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); // When we call getSearchOptions const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_PERIODS, draftComments: {}, @@ -4264,7 +4428,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS_WITH_PERIODS, - {dateFnsLocale: undefined, sortByReportTypeInSearch: true}, + {dateFnsLocale: undefined, convertToDisplayString, sortByReportTypeInSearch: true}, ); // Then only one report should be returned @@ -4283,6 +4447,7 @@ describe('OptionsListUtils', () => { // Given a set of options const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, @@ -4297,7 +4462,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we call filterAndOrderOptions with a an empty search value - const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, '', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); const matchingEntries = filteredOptions.personalDetails.filter((detail) => detail.login === login); // Then there should be 2 unique login entries @@ -4311,6 +4479,7 @@ describe('OptionsListUtils', () => { const OPTIONS_WITH_SELF_DM = createFilteredOptionList(PERSONAL_DETAILS, REPORTS_WITH_SELF_DM, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -4318,6 +4487,7 @@ describe('OptionsListUtils', () => { // Given a set of options with self dm and all betas const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS_WITH_SELF_DM, draftComments: {}, @@ -4331,7 +4501,10 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); // When we call filterAndOrderOptions with a search value - const filteredOptions = filterAndOrderOptions(options, searchTerm, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, searchTerm, COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then the self dm should be on top. expect(filteredOptions.recentReports.at(0)?.isSelfDM).toBe(true); @@ -4341,6 +4514,7 @@ describe('OptionsListUtils', () => { const {options} = getSearchOptions({ translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, options: OPTIONS, reportAttributesDerived: MOCK_REPORT_ATTRIBUTES_DERIVED, draftComments: {}, @@ -4354,8 +4528,14 @@ describe('OptionsListUtils', () => { conciergeReportID: undefined, }); - const multiSpaceQueryResults = filterAndOrderOptions(options, 'Invisible Woman', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); - const spaceSeparatedQueryResults = filterAndOrderOptions(options, 'Invisible Woman', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const multiSpaceQueryResults = filterAndOrderOptions(options, 'Invisible Woman', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); + const spaceSeparatedQueryResults = filterAndOrderOptions(options, 'Invisible Woman', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); expect(multiSpaceQueryResults.recentReports.map((option) => option.reportID)).toEqual(spaceSeparatedQueryResults.recentReports.map((option) => option.reportID)); expect(multiSpaceQueryResults.personalDetails.map((option) => option.accountID)).toEqual(spaceSeparatedQueryResults.personalDetails.map((option) => option.accountID)); @@ -4410,6 +4590,7 @@ describe('OptionsListUtils', () => { const reports = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }).reports; @@ -4425,6 +4606,7 @@ describe('OptionsListUtils', () => { const newReports = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }).reports; @@ -4513,6 +4695,7 @@ describe('OptionsListUtils', () => { const reports = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, archivedMap, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }).reports; @@ -4578,6 +4761,7 @@ describe('OptionsListUtils', () => { isReportArchived: false, personalDetails: PERSONAL_DETAILS, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, translate: translateLocal, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, @@ -4798,6 +4982,7 @@ describe('OptionsListUtils', () => { const optionList = createFilteredOptionList(PERSONAL_DETAILS, {[ROOM_REPORT_ID]: report}, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -4812,6 +4997,7 @@ describe('OptionsListUtils', () => { undefined, { dateFnsLocale: undefined, + convertToDisplayString, showChatPreviewLine: true, includeMultipleParticipantReports: true, personalDetails: PERSONAL_DETAILS, @@ -4849,6 +5035,7 @@ describe('OptionsListUtils', () => { translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, isReportArchived: false, lastActionReport: undefined, @@ -4891,6 +5078,7 @@ describe('OptionsListUtils', () => { translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, isReportArchived: false, lastActionReport: undefined, @@ -4987,6 +5175,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, privateIsArchivedMap, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -5006,6 +5195,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, emptyMap, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -5027,6 +5217,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, privateIsArchivedMap, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -5053,6 +5244,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, privateIsArchivedMap, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); @@ -5076,6 +5268,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, emptyMap, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); @@ -5101,6 +5294,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, privateIsArchivedMap, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); @@ -5132,6 +5326,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, privateIsArchivedMap, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, maxRecentReports: 20, }); @@ -5900,6 +6095,7 @@ describe('OptionsListUtils', () => { const result = createOption({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, accountIDs: [1, 2], personalDetails: PERSONAL_DETAILS, @@ -5940,6 +6136,7 @@ describe('OptionsListUtils', () => { const result = createOption({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, accountIDs: [1, 2], personalDetails: PERSONAL_DETAILS, @@ -5970,6 +6167,7 @@ describe('OptionsListUtils', () => { // Should not throw when reports is undefined const result = createOption({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, accountIDs: [1, 2], personalDetails: PERSONAL_DETAILS, @@ -6127,6 +6325,7 @@ describe('OptionsListUtils', () => { // When we call getReportDisplayOption const result = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails: undefined, personalDetails, @@ -6157,6 +6356,7 @@ describe('OptionsListUtils', () => { // When we call getReportDisplayOption const result = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails: undefined, personalDetails, @@ -6189,6 +6389,7 @@ describe('OptionsListUtils', () => { // When we call getReportDisplayOption const result = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails, personalDetails, @@ -6220,6 +6421,7 @@ describe('OptionsListUtils', () => { // When we call getReportDisplayOption const result = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails: undefined, personalDetails, @@ -6259,6 +6461,7 @@ describe('OptionsListUtils', () => { // When we call getReportDisplayOption with custom personalDetails const result = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails: undefined, personalDetails: customPersonalDetails, @@ -6286,6 +6489,7 @@ describe('OptionsListUtils', () => { // When we call getReportDisplayOption const result = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails: undefined, personalDetails: emptyPersonalDetails, @@ -6308,6 +6512,7 @@ describe('OptionsListUtils', () => { // When we call getReportDisplayOption with undefined report const result = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report: undefined, unknownUserDetails: undefined, personalDetails, @@ -6350,7 +6555,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); @@ -6369,7 +6574,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); @@ -6380,7 +6585,17 @@ describe('OptionsListUtils', () => { it('should work with empty policies collection', () => { const options = {reports: [], personalDetails: []}; - const {options: results} = getValidOptions(options, {}, undefined, loginList, CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, {dateFnsLocale: undefined}, translateLocal); + const {options: results} = getValidOptions( + options, + {}, + undefined, + loginList, + CURRENT_USER_ACCOUNT_ID, + CURRENT_USER_EMAIL, + undefined, + {dateFnsLocale: undefined, convertToDisplayString}, + translateLocal, + ); expect(results).toBeDefined(); expect(results.recentReports).toBeDefined(); @@ -6413,7 +6628,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, betas: [], includeRecentReports: true, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, betas: [], includeRecentReports: true, sortedActions: undefined}, translateLocal, ); @@ -6456,6 +6671,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, policy, {}, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option.text).toBe('Test Workspace'); @@ -6490,6 +6706,7 @@ describe('OptionsListUtils', () => { const option = getReportOption({reportID}, undefined, undefined, selfPersonalDetails, undefined, undefined, undefined, ownerAccountID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option.text).toBe(`Test (${translateLocal('common.you').toLowerCase()})`); @@ -6547,6 +6764,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, policy, personalDetails, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option.text).toBe('Test Workspace with Submit'); @@ -6570,7 +6788,11 @@ describe('OptionsListUtils', () => { reportID, }; - const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, report, CONST.DEFAULT_NUMBER_ID, {translate: translateLocal, dateFnsLocale: undefined}); + const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, report, CONST.DEFAULT_NUMBER_ID, { + translate: translateLocal, + dateFnsLocale: undefined, + convertToDisplayString, + }); expect(option.isDisabled).toBe(true); }); @@ -6614,6 +6836,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, personalDetails, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); // The option.isSelfDM is set by createOption based on the report type @@ -6652,6 +6875,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option.isInvoiceRoom).toBe(true); @@ -6697,6 +6921,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, !!reportNameValuePair?.private_isArchived, POLICY, {}, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option.text).toBe(POLICY.name); @@ -6743,6 +6968,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, !!reportNameValuePair?.private_isArchived, POLICY, {}, undefined, {}, draftReport, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option.isDisabled).toBe(true); @@ -6765,6 +6991,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option.isDisabled).toBeFalsy(); @@ -6784,6 +7011,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, draftReport, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option.isDisabled).toBe(true); @@ -6807,6 +7035,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option.isDisabled).toBeFalsy(); @@ -6831,6 +7060,7 @@ describe('OptionsListUtils', () => { const option = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails: undefined, personalDetails: PERSONAL_DETAILS, @@ -6864,6 +7094,7 @@ describe('OptionsListUtils', () => { const option = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails: undefined, personalDetails: PERSONAL_DETAILS, @@ -6894,6 +7125,7 @@ describe('OptionsListUtils', () => { const option = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails: undefined, personalDetails: PERSONAL_DETAILS, @@ -6928,6 +7160,7 @@ describe('OptionsListUtils', () => { const option = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails: undefined, personalDetails: PERSONAL_DETAILS, @@ -6962,6 +7195,7 @@ describe('OptionsListUtils', () => { const option = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails: undefined, personalDetails: PERSONAL_DETAILS, @@ -6996,6 +7230,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option.isSelected).toBe(true); @@ -7020,6 +7255,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, undefined, {}, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option).toBeDefined(); @@ -7045,6 +7281,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option).toBeDefined(); @@ -7084,6 +7321,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, testPersonalDetails, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option).toBeDefined(); @@ -7149,6 +7387,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, policy, testPersonalDetails, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option).toBeDefined(); @@ -7177,6 +7416,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option).toBeDefined(); @@ -7202,6 +7442,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, undefined, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option).toBeDefined(); @@ -7255,6 +7496,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, testPersonalDetails, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option).toBeDefined(); @@ -7280,6 +7522,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, {}, conciergeReportID, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option).toBeDefined(); @@ -7302,6 +7545,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option).toBeDefined(); @@ -7342,6 +7586,7 @@ describe('OptionsListUtils', () => { const option = getReportOption(participant, undefined, POLICY, testPersonalDetails, conciergeReportID, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); expect(option).toBeDefined(); @@ -7365,10 +7610,12 @@ describe('OptionsListUtils', () => { const optionWithConcierge = getReportOption(participant, undefined, POLICY, {}, differentConciergeReportID, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); const optionWithoutConcierge = getReportOption(participant, undefined, POLICY, {}, undefined, undefined, undefined, CONST.DEFAULT_NUMBER_ID, { translate: translateLocal, dateFnsLocale: undefined, + convertToDisplayString, }); // Both should produce the same result since the IDs don't match @@ -7432,7 +7679,7 @@ describe('OptionsListUtils', () => { testPersonalDetails, report, undefined, - {translate: translateLocal, dateFnsLocale: undefined}, + {translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString}, CURRENT_USER_ACCOUNT_ID, ); @@ -7461,7 +7708,15 @@ describe('OptionsListUtils', () => { const translateWithMarker: LocalizedTranslate = (path, ...parameters) => (path === 'workspace.common.workspace' ? 'WorkspaceMarker' : translateLocal(path, ...parameters)); const participant = {reportID, policyID: testPolicyID, isPolicyExpenseChat: true, selected: false}; - const option = getPolicyExpenseReportOption(participant, undefined, {}, report, undefined, {translate: translateWithMarker, dateFnsLocale: undefined}, CURRENT_USER_ACCOUNT_ID); + const option = getPolicyExpenseReportOption( + participant, + undefined, + {}, + report, + undefined, + {translate: translateWithMarker, dateFnsLocale: undefined, convertToDisplayString}, + CURRENT_USER_ACCOUNT_ID, + ); // The subtitle resolves to the marker, proving the option builder used the injected translate (not translateLocal) expect(option.alternateText).toBe('WorkspaceMarker'); @@ -7529,7 +7784,7 @@ describe('OptionsListUtils', () => { testPersonalDetails, report, undefined, - {translate: translateLocal, dateFnsLocale: undefined}, + {translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString}, CURRENT_USER_ACCOUNT_ID, ); @@ -7576,7 +7831,15 @@ describe('OptionsListUtils', () => { }; // Should not throw when personalDetails is empty - const option = getPolicyExpenseReportOption(participant, undefined, {}, report, undefined, {translate: translateLocal, dateFnsLocale: undefined}, CURRENT_USER_ACCOUNT_ID); + const option = getPolicyExpenseReportOption( + participant, + undefined, + {}, + report, + undefined, + {translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString}, + CURRENT_USER_ACCOUNT_ID, + ); expect(option).toBeDefined(); expect(option.text).toBe('Workspace Without Details'); @@ -7621,7 +7884,15 @@ describe('OptionsListUtils', () => { }; // Should not throw when personalDetails is undefined - const option = getPolicyExpenseReportOption(participant, undefined, undefined, report, undefined, {translate: translateLocal, dateFnsLocale: undefined}, CURRENT_USER_ACCOUNT_ID); + const option = getPolicyExpenseReportOption( + participant, + undefined, + undefined, + report, + undefined, + {translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString}, + CURRENT_USER_ACCOUNT_ID, + ); expect(option).toBeDefined(); expect(option.text).toBe('Workspace Undefined Details'); @@ -7680,7 +7951,7 @@ describe('OptionsListUtils', () => { {}, report, undefined, - {translate: translateLocal, dateFnsLocale: undefined}, + {translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString}, CURRENT_USER_ACCOUNT_ID, ); @@ -7691,7 +7962,7 @@ describe('OptionsListUtils', () => { {}, report, undefined, - {translate: translateLocal, dateFnsLocale: undefined}, + {translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString}, CURRENT_USER_ACCOUNT_ID, ); @@ -7737,7 +8008,7 @@ describe('OptionsListUtils', () => { testPersonalDetails, report, undefined, - {translate: translateLocal, dateFnsLocale: undefined}, + {translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString}, CURRENT_USER_ACCOUNT_ID, ); const optionWithDifferentUser = getPolicyExpenseReportOption( @@ -7746,7 +8017,7 @@ describe('OptionsListUtils', () => { testPersonalDetails, report, undefined, - {translate: translateLocal, dateFnsLocale: undefined}, + {translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString}, 9999, ); @@ -7811,7 +8082,7 @@ describe('OptionsListUtils', () => { testPersonalDetails, report, undefined, - {translate: translateLocal, dateFnsLocale: undefined}, + {translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString}, CURRENT_USER_ACCOUNT_ID, ); @@ -7858,7 +8129,15 @@ describe('OptionsListUtils', () => { isPolicyExpenseChat: true, }; - const option = getPolicyExpenseReportOption(participant, undefined, {}, report, undefined, {translate: translateLocal, dateFnsLocale: undefined}, CURRENT_USER_ACCOUNT_ID); + const option = getPolicyExpenseReportOption( + participant, + undefined, + {}, + report, + undefined, + {translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString}, + CURRENT_USER_ACCOUNT_ID, + ); expect(option).toBeDefined(); expect(option?.private_isArchived).toBeUndefined(); @@ -7956,6 +8235,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, undefined, translateLocal, + convertToDisplayString, undefined, formatPersonalDetails, true, @@ -7991,6 +8271,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, undefined, translateLocal, + convertToDisplayString, undefined, formatPersonalDetails, true, @@ -8041,6 +8322,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, undefined, translateLocal, + convertToDisplayString, undefined, formatPersonalDetails, true, @@ -8084,6 +8366,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, undefined, translateLocal, + convertToDisplayString, undefined, formatPersonalDetails, false, @@ -8124,6 +8407,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, undefined, translateLocal, + convertToDisplayString, undefined, formatPersonalDetails, true, @@ -8164,6 +8448,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, undefined, translateLocal, + convertToDisplayString, undefined, formatPersonalDetails, true, @@ -8179,7 +8464,20 @@ describe('OptionsListUtils', () => { }); it('should return empty section when no selectedOptions are provided', () => { - const result = formatSectionsFromSearchTerm('', [], [], [], {}, CURRENT_USER_ACCOUNT_ID, undefined, translateLocal, undefined, formatPersonalDetails, true); + const result = formatSectionsFromSearchTerm( + '', + [], + [], + [], + {}, + CURRENT_USER_ACCOUNT_ID, + undefined, + translateLocal, + convertToDisplayString, + undefined, + formatPersonalDetails, + true, + ); expect(result.section.data).toHaveLength(0); }); @@ -8227,6 +8525,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, undefined, translateLocal, + convertToDisplayString, undefined, formatPersonalDetails, true, @@ -8246,6 +8545,7 @@ describe('OptionsListUtils', () => { it('should not return userToInvite for plain text name when shouldAcceptName is false', () => { const result = getUserToInviteOption({ dateFnsLocale: undefined, + convertToDisplayString, searchValue: 'Jeff Amazon', personalDetails: PERSONAL_DETAILS, loginList: {}, @@ -8257,6 +8557,7 @@ describe('OptionsListUtils', () => { it('should return userToInvite for plain text name when shouldAcceptName is true', () => { const result = getUserToInviteOption({ dateFnsLocale: undefined, + convertToDisplayString, searchValue: 'Jeff Amazon', personalDetails: PERSONAL_DETAILS, shouldAcceptName: true, @@ -8279,7 +8580,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); @@ -8299,12 +8600,15 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); // When we call filterAndOrderOptions with the reports parameter - const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS); + const filteredOptions = filterAndOrderOptions(options, 'spider', COUNTRY_CODE, loginList, CURRENT_USER_EMAIL, CURRENT_USER_ACCOUNT_ID, PERSONAL_DETAILS, { + dateFnsLocale: undefined, + convertToDisplayString, + }); // Then the function should complete without errors and return valid results expect(filteredOptions).toBeDefined(); @@ -8316,6 +8620,7 @@ describe('OptionsListUtils', () => { // When we call getSearchOptions with reports in the config const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, draftComments: {}, @@ -8338,6 +8643,7 @@ describe('OptionsListUtils', () => { const sortedActions = {}; const {options} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: OPTIONS, draftComments: {}, @@ -8359,6 +8665,7 @@ describe('OptionsListUtils', () => { // Given a valid email search value and reports collection const result = getUserToInviteOption({ dateFnsLocale: undefined, + convertToDisplayString, searchValue: 'newuser@example.com', loginList: {}, currentUserEmail: CURRENT_USER_EMAIL, @@ -8380,7 +8687,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); @@ -8400,7 +8707,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined}, + {dateFnsLocale: undefined, convertToDisplayString}, translateLocal, ); @@ -8444,6 +8751,7 @@ describe('OptionsListUtils', () => { // When we call createOption with the linked chat report const result = createOption({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, accountIDs: [1, 2], personalDetails: PERSONAL_DETAILS, @@ -8483,6 +8791,7 @@ describe('OptionsListUtils', () => { // When we call getReportDisplayOption with chat report const option = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails: undefined, personalDetails: PERSONAL_DETAILS, @@ -8537,7 +8846,7 @@ describe('OptionsListUtils', () => { PERSONAL_DETAILS, report, undefined, - {translate: translateLocal, dateFnsLocale: undefined}, + {translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString}, CURRENT_USER_ACCOUNT_ID, ); @@ -8566,6 +8875,7 @@ describe('OptionsListUtils', () => { // When the threaded conciergeReportID matches the report const conciergeOption = createOptionFromReport({ dateFnsLocale: undefined, + convertToDisplayString, report, personalDetails: PERSONAL_DETAILS, privateIsArchived: undefined, @@ -8578,6 +8888,7 @@ describe('OptionsListUtils', () => { // And an identical report with a non-matching conciergeReportID is not treated as Concierge const regularOption = createOptionFromReport({ dateFnsLocale: undefined, + convertToDisplayString, report, personalDetails: PERSONAL_DETAILS, privateIsArchived: undefined, @@ -8607,6 +8918,7 @@ describe('OptionsListUtils', () => { const result = createOptionFromReport({ dateFnsLocale: undefined, + convertToDisplayString, report, personalDetails: PERSONAL_DETAILS, privateIsArchived: undefined, @@ -8639,6 +8951,7 @@ describe('OptionsListUtils', () => { const result = createOptionFromReport({ dateFnsLocale: undefined, + convertToDisplayString, report, personalDetails: PERSONAL_DETAILS, privateIsArchived: true, @@ -8670,6 +8983,7 @@ describe('OptionsListUtils', () => { const result = createOptionFromReport({ dateFnsLocale: undefined, + convertToDisplayString, report, personalDetails: PERSONAL_DETAILS, privateIsArchived: undefined, @@ -8701,6 +9015,7 @@ describe('OptionsListUtils', () => { const result = createOptionFromReport({ dateFnsLocale: undefined, + convertToDisplayString, report, personalDetails: PERSONAL_DETAILS, privateIsArchived: undefined, @@ -8733,6 +9048,7 @@ describe('OptionsListUtils', () => { const config = {showPersonalDetails: true}; const result = createOptionFromReport({ dateFnsLocale: undefined, + convertToDisplayString, report, personalDetails: PERSONAL_DETAILS, privateIsArchived: undefined, @@ -8770,6 +9086,7 @@ describe('OptionsListUtils', () => { const roomOption = createOptionFromReport({ dateFnsLocale: undefined, + convertToDisplayString, report, personalDetails: PERSONAL_DETAILS, privateIsArchived: undefined, @@ -8779,6 +9096,7 @@ describe('OptionsListUtils', () => { }); const personalDetailsOption = createOptionFromReport({ dateFnsLocale: undefined, + convertToDisplayString, report, personalDetails: PERSONAL_DETAILS, privateIsArchived: undefined, @@ -8819,6 +9137,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList({}, reportsToCollection(reports), undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, maxRecentReports: 2, includeP2P: false, @@ -8833,6 +9152,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList({}, reportsToCollection(reports), undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, maxRecentReports: 1, includeP2P: false, @@ -8850,6 +9170,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList({}, reportsToCollection(reports), undefined, privateIsArchivedMap, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, maxRecentReports: 1, includeP2P: false, @@ -8864,6 +9185,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList({}, reportsToCollection(reports), undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, maxRecentReports: 1, isSearching: true, @@ -8879,6 +9201,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList({}, reportsToCollection(reports), undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, maxRecentReports: 0, includeP2P: false, @@ -8890,6 +9213,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, maxRecentReports: 5, }); @@ -8947,6 +9271,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList({}, Object.fromEntries(reportsWithDates.map((report) => [report.reportID, report])), undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, maxRecentReports: 3, includeP2P: false, conciergeReportID: undefined, @@ -8959,6 +9284,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, includeP2P: true, }); @@ -8972,6 +9298,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, includeP2P: false, }); @@ -8984,6 +9311,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, {}, undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); @@ -8995,6 +9323,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, undefined, undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); @@ -9029,6 +9358,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, reportsCollection, undefined, privateIsArchivedMap, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, maxRecentReports: 10, }); @@ -9040,6 +9370,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -9055,7 +9386,7 @@ describe('OptionsListUtils', () => { undefined, {}, {}, - {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, conciergeReportID: undefined, isSearching: true, maxRecentReports: 2}, + {currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, convertToDisplayString, conciergeReportID: undefined, isSearching: true, maxRecentReports: 2}, ); expect(result).toBeDefined(); @@ -9066,6 +9397,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); @@ -9080,6 +9412,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, deferContactsUntilSearch: true, }); @@ -9092,6 +9425,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, {}, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, deferContactsUntilSearch: true, isSearching: true, @@ -9104,6 +9438,7 @@ describe('OptionsListUtils', () => { const first = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); const firstOption = first.personalDetails.at(0); @@ -9115,6 +9450,7 @@ describe('OptionsListUtils', () => { const second = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); const secondOption = second.personalDetails.at(0); @@ -9133,11 +9469,13 @@ describe('OptionsListUtils', () => { const first = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); const second = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: '1', }); @@ -9154,6 +9492,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); // Report options still carry fully-built icons; personal detail shells do not. @@ -9169,6 +9508,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); const personalDetailItem = result.personalDetails.at(0)?.item; @@ -9204,7 +9544,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeRecentReports: false, recentAttendees, maxRecentReportElements: 5, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, includeRecentReports: false, recentAttendees, maxRecentReportElements: 5, sortedActions: undefined}, translateLocal, ); @@ -9222,7 +9562,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeRecentReports: false, recentAttendees, maxRecentReportElements: 5, searchString: 'john', sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, includeRecentReports: false, recentAttendees, maxRecentReportElements: 5, searchString: 'john', sortedActions: undefined}, translateLocal, ); @@ -9236,6 +9576,7 @@ describe('OptionsListUtils', () => { const result = createFilteredOptionList(PERSONAL_DETAILS, REPORTS, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, allPolicies, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, }); expect(result).toBeDefined(); @@ -9263,6 +9604,7 @@ describe('OptionsListUtils', () => { const result = createOptionFromReport({ dateFnsLocale: undefined, + convertToDisplayString, report, personalDetails: PERSONAL_DETAILS, privateIsArchived: undefined, @@ -9292,6 +9634,7 @@ describe('OptionsListUtils', () => { const result = getReportDisplayOption({ dateFnsLocale: undefined, + convertToDisplayString, report, unknownUserDetails: undefined, personalDetails: PERSONAL_DETAILS, @@ -9335,7 +9678,7 @@ describe('OptionsListUtils', () => { PERSONAL_DETAILS, report, POLICY, - {translate: translateLocal, dateFnsLocale: undefined}, + {translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString}, CURRENT_USER_ACCOUNT_ID, ); expect(result).toBeDefined(); @@ -9343,7 +9686,7 @@ describe('OptionsListUtils', () => { }); it('formatSectionsFromSearchTerm should accept policy parameter', () => { - const result = formatSectionsFromSearchTerm('', [], [], [], {}, CURRENT_USER_ACCOUNT_ID, allPolicies, translateLocal, undefined, PERSONAL_DETAILS, true); + const result = formatSectionsFromSearchTerm('', [], [], [], {}, CURRENT_USER_ACCOUNT_ID, allPolicies, translateLocal, convertToDisplayString, undefined, PERSONAL_DETAILS, true); expect(result).toBeDefined(); expect(result.section).toBeDefined(); }); @@ -9417,7 +9760,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeRecentReports: true, includeMultipleParticipantReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions}, + {dateFnsLocale: undefined, convertToDisplayString, includeRecentReports: true, includeMultipleParticipantReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions}, translateLocal, ); @@ -9476,7 +9819,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeRecentReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions}, + {dateFnsLocale: undefined, convertToDisplayString, includeRecentReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions}, translateLocal, ); @@ -9532,7 +9875,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeRecentReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions: undefined}, + {dateFnsLocale: undefined, convertToDisplayString, includeRecentReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions: undefined}, translateLocal, ); @@ -9614,7 +9957,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeRecentReports: true, includeMultipleParticipantReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions}, + {dateFnsLocale: undefined, convertToDisplayString, includeRecentReports: true, includeMultipleParticipantReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions}, translateLocal, ); @@ -9689,7 +10032,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeRecentReports: true, sortedActions}, + {dateFnsLocale: undefined, convertToDisplayString, includeRecentReports: true, sortedActions}, translateLocal, ); @@ -9754,7 +10097,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeRecentReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions}, + {dateFnsLocale: undefined, convertToDisplayString, includeRecentReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions}, translateLocal, ); @@ -9871,7 +10214,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeRecentReports: true, includeMultipleParticipantReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions}, + {dateFnsLocale: undefined, convertToDisplayString, includeRecentReports: true, includeMultipleParticipantReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions}, translateLocal, ); @@ -9932,7 +10275,7 @@ describe('OptionsListUtils', () => { CURRENT_USER_ACCOUNT_ID, CURRENT_USER_EMAIL, undefined, - {dateFnsLocale: undefined, includeRecentReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions: {[reportID]: [commentAction]}}, + {dateFnsLocale: undefined, convertToDisplayString, includeRecentReports: true, action: CONST.IOU.ACTION.CREATE, sortedActions: {[reportID]: [commentAction]}}, translateLocal, ); @@ -9983,6 +10326,7 @@ describe('OptionsListUtils', () => { const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: {reports: [inputOption], personalDetails: []}, draftComments: {}, @@ -10051,6 +10395,7 @@ describe('OptionsListUtils', () => { const {options: results} = getSearchOptions({ dateFnsLocale: undefined, + convertToDisplayString, translate: translateLocal, options: {reports: [inputOption], personalDetails: []}, draftComments: {}, diff --git a/tests/unit/ReportAlternateTextParityTest.ts b/tests/unit/ReportAlternateTextParityTest.ts index 6997f258584c..d2078a40ac0e 100644 --- a/tests/unit/ReportAlternateTextParityTest.ts +++ b/tests/unit/ReportAlternateTextParityTest.ts @@ -15,7 +15,7 @@ import type {OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import {convertToDisplayString, formatPhoneNumber, localeCompare, translateLocal} from '../utils/TestHelper'; +import {convertToDisplayString, convertToDisplayStringWithoutCurrency, formatPhoneNumber, localeCompare, translateLocal} from '../utils/TestHelper'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; const CURRENT_USER_LOGIN = 'test@example.com'; @@ -99,6 +99,7 @@ function getAlternateText({ translate: translateLocal, dateFnsLocale: undefined, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, isReportArchived, lastActionReport, diff --git a/tests/unit/ReportAlternateTextUtilsTest.ts b/tests/unit/ReportAlternateTextUtilsTest.ts index 540ec5e1097a..5c6d6094aad0 100644 --- a/tests/unit/ReportAlternateTextUtilsTest.ts +++ b/tests/unit/ReportAlternateTextUtilsTest.ts @@ -55,7 +55,7 @@ import {createRandomReport} from '../utils/collections/reports'; import createRandomTransaction from '../utils/collections/transaction'; import createMock from '../utils/createMock'; import * as LHNTestUtils from '../utils/LHNTestUtils'; -import {convertToDisplayString, formatPhoneNumber, getCurrencyDecimalsLocal, localeCompare, translateLocal} from '../utils/TestHelper'; +import {convertToDisplayString, convertToDisplayStringWithoutCurrency, formatPhoneNumber, getCurrencyDecimalsLocal, localeCompare, translateLocal} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; @@ -137,6 +137,7 @@ function getAlternateText({report = makeReport(), lastAction, lastMessageTextFro formatPhoneNumber, dateFnsLocale: undefined, convertToDisplayString, + convertToDisplayStringWithoutCurrency, }); } @@ -573,6 +574,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -640,6 +642,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -692,6 +695,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -744,6 +748,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -796,6 +801,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -847,6 +853,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -886,6 +893,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -951,6 +959,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1002,6 +1011,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1039,6 +1049,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1070,6 +1081,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1101,6 +1113,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1134,6 +1147,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1164,6 +1178,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1192,6 +1207,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1219,6 +1235,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1245,6 +1262,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1271,6 +1289,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, translate: translateLocal, @@ -1296,6 +1315,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, translate: translateLocal, @@ -1321,6 +1341,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, translate: translateLocal, @@ -1349,6 +1370,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1375,6 +1397,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1401,6 +1424,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1430,6 +1454,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1456,6 +1481,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1488,6 +1514,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1514,6 +1541,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1540,6 +1568,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1565,6 +1594,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1590,6 +1620,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1619,6 +1650,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1648,6 +1680,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1676,6 +1709,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1705,6 +1739,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1730,6 +1765,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1756,6 +1792,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1782,6 +1819,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1812,6 +1850,7 @@ describe('ReportAlternateTextUtils', () => { // When getting the last message text for the report const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1844,6 +1883,7 @@ describe('ReportAlternateTextUtils', () => { const expectedVisibleText = ''; const result = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1895,6 +1935,7 @@ describe('ReportAlternateTextUtils', () => { // When we get the last message text while the mentioned user is absent from personal details const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, personalDetails: undefined, translate: translateLocal, @@ -1919,6 +1960,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -1954,6 +1996,7 @@ describe('ReportAlternateTextUtils', () => { const result = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -2002,6 +2045,7 @@ describe('ReportAlternateTextUtils', () => { const result = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -2051,6 +2095,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -2090,6 +2135,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -2125,6 +2171,7 @@ describe('ReportAlternateTextUtils', () => { }); const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -2168,6 +2215,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -2210,6 +2258,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, @@ -2249,6 +2298,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, personalDetails: undefined, translate: translateWithUnavailableMarker, @@ -2284,6 +2334,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, translate: translateLocal, @@ -2318,6 +2369,7 @@ describe('ReportAlternateTextUtils', () => { const lastMessage = getLastMessageTextForReport({ dateFnsLocale: undefined, + convertToDisplayString, conciergeReportID: undefined, currentUserAccountID: CURRENT_USER_ACCOUNT_ID, personalDetails: undefined, diff --git a/tests/unit/ReportNameUtilsTest.ts b/tests/unit/ReportNameUtilsTest.ts index 0ca8e449c1be..de53730281a4 100644 --- a/tests/unit/ReportNameUtilsTest.ts +++ b/tests/unit/ReportNameUtilsTest.ts @@ -1,6 +1,5 @@ import type {LocalizedTranslate} from '@components/LocaleContextProvider'; -import {convertToDisplayString} from '@libs/CurrencyUtils'; import {translate} from '@libs/Localize'; import { buildReportNameFromParticipantNames, @@ -30,7 +29,7 @@ import {createAdminRoom, createExpenseReport, createPolicyExpenseChat, createReg import createRandomTransaction from '../utils/collections/transaction'; import createMock from '../utils/createMock'; import {fakePersonalDetails} from '../utils/LHNTestUtils'; -import {formatPhoneNumber, translateLocal} from '../utils/TestHelper'; +import {convertToDisplayString, convertToDisplayStringWithoutCurrency, formatPhoneNumber, getCurrencySymbolLocal, translateLocal} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; const currentUserLogin = 'lagertha2@vikings.net'; @@ -48,6 +47,9 @@ describe('ReportNameUtils', () => { ) => computeReportNameOriginal({ dateFnsLocale: undefined, + convertToDisplayString, + convertToDisplayStringWithoutCurrency, + getCurrencySymbol: getCurrencySymbolLocal, conciergeReportID: undefined, report, reports, @@ -306,6 +308,9 @@ describe('ReportNameUtils', () => { const translateWithYouMarker: LocalizedTranslate = (path, ...parameters) => (path === 'common.you' ? 'You Marker' : translateLocal(path, ...parameters)); const name = computeReportNameOriginal({ dateFnsLocale: undefined, + convertToDisplayString, + convertToDisplayStringWithoutCurrency, + getCurrencySymbol: getCurrencySymbolLocal, conciergeReportID: undefined, report, reports: emptyCollections.reports, @@ -694,6 +699,9 @@ describe('ReportNameUtils', () => { const name = computeReportNameOriginal({ dateFnsLocale: undefined, + convertToDisplayString, + convertToDisplayStringWithoutCurrency, + getCurrencySymbol: getCurrencySymbolLocal, conciergeReportID: undefined, report: thread, reports: emptyCollections.reports, @@ -1930,6 +1938,7 @@ describe('ReportNameUtils', () => { const reportName = getMoneyRequestReportName({ report: iouReport, translate: translateWithHiddenMarker, + convertToDisplayString, personalDetailsList: undefined, linkedTransactions: [], }); @@ -1955,7 +1964,13 @@ describe('ReportNameUtils', () => { currency: 'USD', }; - const reportName = getMoneyRequestReportName({report: invoiceReport, personalDetailsList: participantsPersonalDetails, linkedTransactions: [], translate: translateLocal}); + const reportName = getMoneyRequestReportName({ + report: invoiceReport, + personalDetailsList: participantsPersonalDetails, + linkedTransactions: [], + translate: translateLocal, + convertToDisplayString, + }); expect(reportName?.replaceAll(/\s+/g, ' ')).toContain('Ragnar Lothbrok'); }); @@ -1985,6 +2000,7 @@ describe('ReportNameUtils', () => { personalDetailsList: undefined, linkedTransactions: [], translate: translateLocal, + convertToDisplayString, }); // Then it should return "New Report" @@ -2033,6 +2049,7 @@ describe('ReportNameUtils', () => { personalDetailsList: undefined, linkedTransactions: [], translate: translateLocal, + convertToDisplayString, }); // Then it should NOT return empty string — it should fall through to dynamic name computation @@ -2095,6 +2112,7 @@ describe('ReportNameUtils', () => { personalDetailsList: undefined, linkedTransactions: [nonReimbursableTransaction], translate: translateLocal, + convertToDisplayString, }); // Then it should use the "spent" wording with the owner's display name @@ -2151,6 +2169,7 @@ describe('ReportNameUtils', () => { personalDetailsList: undefined, linkedTransactions: [], translate: translateWithUnavailableMarker, + convertToDisplayString, }); expect(reportName).toContain('UnavailableWorkspaceMarker'); @@ -2294,6 +2313,9 @@ describe('ReportNameUtils', () => { // When the threaded conciergeReportID matches the report const nameWithMatchingID = computeReportNameOriginal({ dateFnsLocale: undefined, + convertToDisplayString, + convertToDisplayStringWithoutCurrency, + getCurrencySymbol: getCurrencySymbolLocal, conciergeReportID: 'concierge-name-1', report, transactions: undefined, @@ -2308,6 +2330,9 @@ describe('ReportNameUtils', () => { // And an identical report with a non-matching conciergeReportID keeps its regular name const nameWithDifferentID = computeReportNameOriginal({ dateFnsLocale: undefined, + convertToDisplayString, + convertToDisplayStringWithoutCurrency, + getCurrencySymbol: getCurrencySymbolLocal, conciergeReportID: 'a-different-report-id', report, transactions: undefined, diff --git a/tests/unit/ReportUtilsTest.ts b/tests/unit/ReportUtilsTest.ts index b14f765c699e..7986e56681f3 100644 --- a/tests/unit/ReportUtilsTest.ts +++ b/tests/unit/ReportUtilsTest.ts @@ -296,7 +296,15 @@ import createRandomTransaction from '../utils/collections/transaction'; import createMock from '../utils/createMock'; import * as LHNTestUtils from '../utils/LHNTestUtils'; import {fakePersonalDetails} from '../utils/LHNTestUtils'; -import {convertToDisplayString, formatPhoneNumber, getCurrencyDecimalsLocal, getCurrencySymbolLocal, localeCompare, translateLocal} from '../utils/TestHelper'; +import { + convertToDisplayString, + convertToDisplayStringWithoutCurrency, + formatPhoneNumber, + getCurrencyDecimalsLocal, + getCurrencySymbolLocal, + localeCompare, + translateLocal, +} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; type ClosedReportActionMessage = ReportAction['message']; @@ -377,6 +385,9 @@ const computeReportName = ( currentUserAccountID: currentUserID, currentUserLogin: currentUserEmail, translate: translateLocal, + convertToDisplayString, + convertToDisplayStringWithoutCurrency, + getCurrencySymbol: getCurrencySymbolLocal, conciergeReportID, reportTransactions: buildTransactionsByReportID(transactions), isTrackIntentUser: false, @@ -22168,7 +22179,7 @@ describe('ReportUtils', () => { await waitForBatchedUpdates(); const action = {...createRandomReportAction(1)}; - const result = getChatListItemReportName(action, conciergeReport, undefined, conciergeReportID, [], translateLocal, undefined); + const result = getChatListItemReportName(action, conciergeReport, undefined, conciergeReportID, [], translateLocal, convertToDisplayString, undefined); expect(result).toBe(CONST.CONCIERGE_DISPLAY_NAME); }); @@ -22182,7 +22193,7 @@ describe('ReportUtils', () => { await waitForBatchedUpdates(); const action = {...createRandomReportAction(2)}; - const result = getChatListItemReportName(action, regularReport, undefined, conciergeReportID, [], translateLocal, undefined); + const result = getChatListItemReportName(action, regularReport, undefined, conciergeReportID, [], translateLocal, convertToDisplayString, undefined); expect(result).not.toBe(CONST.CONCIERGE_DISPLAY_NAME); }); @@ -22192,7 +22203,7 @@ describe('ReportUtils', () => { type: CONST.REPORT.TYPE.CHAT, }; const action = {...createRandomReportAction(3), reportName: 'Custom Action Name'}; - const result = getChatListItemReportName(action, conciergeReport, undefined, conciergeReportID, [], translateLocal, undefined); + const result = getChatListItemReportName(action, conciergeReport, undefined, conciergeReportID, [], translateLocal, convertToDisplayString, undefined); expect(result).toBe('Custom Action Name'); }); @@ -22202,7 +22213,7 @@ describe('ReportUtils', () => { type: CONST.REPORT.TYPE.CHAT, }; const action = {...createRandomReportAction(4)}; - const result = getChatListItemReportName(action, conciergeReport, undefined, conciergeReportID, [], translateLocal, undefined); + const result = getChatListItemReportName(action, conciergeReport, undefined, conciergeReportID, [], translateLocal, convertToDisplayString, undefined); expect(result).toBe(CONST.CONCIERGE_DISPLAY_NAME); }); @@ -22223,7 +22234,7 @@ describe('ReportUtils', () => { const translateWithMarker: LocalizedTranslate = (path, ...parameters) => (path === 'iou.payerOwesAmount' ? 'PayerOwesMarker' : translateLocal(path, ...parameters)); const action = {...createRandomReportAction(5)}; - const result = getChatListItemReportName(action, invoiceReport, parentChatReport, undefined, [], translateWithMarker, undefined); + const result = getChatListItemReportName(action, invoiceReport, parentChatReport, undefined, [], translateWithMarker, convertToDisplayString, undefined); expect(result).toBe('PayerOwesMarker'); }); @@ -22243,7 +22254,7 @@ describe('ReportUtils', () => { }; const action = {...createRandomReportAction(6)}; - const result = getChatListItemReportName(action, invoiceReport, parentChatReport, undefined, [], translateLocal, undefined); + const result = getChatListItemReportName(action, invoiceReport, parentChatReport, undefined, [], translateLocal, convertToDisplayString, undefined); expect(result).toBe('Invoice #42'); }); @@ -22281,7 +22292,7 @@ describe('ReportUtils', () => { }; const action = {...createRandomReportAction(7)}; - const result = getChatListItemReportName(action, invoiceReport, nonInvoiceParent, undefined, [], translateWithMarker, undefined); + const result = getChatListItemReportName(action, invoiceReport, nonInvoiceParent, undefined, [], translateWithMarker, convertToDisplayString, undefined); expect(result).toBe('PayerOwesMarker'); }); @@ -22296,7 +22307,7 @@ describe('ReportUtils', () => { }; const action = {...createRandomReportAction(8)}; - const result = getChatListItemReportName(action, invoiceReport, invoiceRoom, undefined, [], translateWithMarker, undefined); + const result = getChatListItemReportName(action, invoiceReport, invoiceRoom, undefined, [], translateWithMarker, convertToDisplayString, undefined); expect(result).toBe('PayerOwesMarker'); }); @@ -22310,7 +22321,7 @@ describe('ReportUtils', () => { }; const action = {...createRandomReportAction(9)}; - getChatListItemReportName(action, invoiceReport, invoiceRoom, undefined, [], translateWithMarker, undefined); + getChatListItemReportName(action, invoiceReport, invoiceRoom, undefined, [], translateWithMarker, convertToDisplayString, undefined); expect(invoiceReport.chatReportID).toBeUndefined(); }); @@ -22336,7 +22347,7 @@ describe('ReportUtils', () => { }; const action = {...createRandomReportAction(10)}; - const result = getChatListItemReportName(action, invoiceThread, parentInvoiceReport, undefined, [], translateWithMarker, undefined); + const result = getChatListItemReportName(action, invoiceThread, parentInvoiceReport, undefined, [], translateWithMarker, convertToDisplayString, undefined); expect(result).toBe('PayerOwesMarker'); }); diff --git a/tests/unit/SearchAutocompleteListTest.tsx b/tests/unit/SearchAutocompleteListTest.tsx index 9d422662c385..d9565b9e49cf 100644 --- a/tests/unit/SearchAutocompleteListTest.tsx +++ b/tests/unit/SearchAutocompleteListTest.tsx @@ -176,6 +176,7 @@ const CURRENT_USER_ACCOUNT_ID = 1; const mockedOptions = createFilteredOptionList(mockedPersonalDetails, mockedReports, undefined, EMPTY_PRIVATE_IS_ARCHIVED_MAP, undefined, { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString: TestHelper.convertToDisplayString, conciergeReportID: undefined, isSearching: true, }); @@ -459,6 +460,7 @@ describe('SearchAutocompleteList', () => { { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString: TestHelper.convertToDisplayString, conciergeReportID: undefined, isSearching: true, }, @@ -548,6 +550,7 @@ describe('SearchAutocompleteList', () => { { currentUserAccountID: CURRENT_USER_ACCOUNT_ID, dateFnsLocale: undefined, + convertToDisplayString: TestHelper.convertToDisplayString, conciergeReportID: undefined, isSearching: true, }, diff --git a/tests/unit/SidebarUtilsTest.ts b/tests/unit/SidebarUtilsTest.ts index 27d54cb59572..4401a31745b1 100644 --- a/tests/unit/SidebarUtilsTest.ts +++ b/tests/unit/SidebarUtilsTest.ts @@ -41,7 +41,7 @@ import {createSidebarReportsCollection, createSidebarTestData} from '../utils/co import createRandomTransaction from '../utils/collections/transaction'; import createMock from '../utils/createMock'; import * as LHNTestUtils from '../utils/LHNTestUtils'; -import {convertToDisplayString, getCurrencyDecimalsLocal, localeCompare, translateLocal, formatPhoneNumber} from '../utils/TestHelper'; +import {convertToDisplayString, convertToDisplayStringWithoutCurrency, getCurrencyDecimalsLocal, localeCompare, translateLocal, formatPhoneNumber} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct'; @@ -380,6 +380,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: undefined, lastActionReport: undefined, @@ -405,6 +406,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: undefined, lastActionReport: undefined, @@ -1532,6 +1534,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -1601,6 +1604,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -1645,6 +1649,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -1688,6 +1693,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -1731,6 +1737,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -1780,6 +1787,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -1823,6 +1831,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: enabledAction, lastActionReport: undefined, @@ -1859,6 +1868,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: disabledAction, lastActionReport: undefined, @@ -1902,6 +1912,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: enabledAction, lastActionReport: undefined, @@ -1938,6 +1949,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: disabledAction, lastActionReport: undefined, @@ -1987,6 +1999,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: action, lastActionReport: undefined, @@ -2030,6 +2043,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: enabledAction, lastActionReport: undefined, @@ -2066,6 +2080,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: disabledAction, lastActionReport: undefined, @@ -2108,6 +2123,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: companyPaysAction, lastActionReport: undefined, @@ -2143,6 +2159,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: employeePaysAction, lastActionReport: undefined, @@ -2186,6 +2203,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, formatPhoneNumber, lastAction: enabledAction, @@ -2222,6 +2240,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, formatPhoneNumber, lastAction: disabledAction, @@ -2265,6 +2284,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -2308,6 +2328,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -2351,6 +2372,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -2394,6 +2416,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -2437,6 +2460,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -2480,6 +2504,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -2523,6 +2548,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -2594,6 +2620,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -2652,6 +2679,7 @@ describe('SidebarUtils', () => { lastAction: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastActionReport: undefined, isReportArchived: undefined, @@ -2699,6 +2727,7 @@ describe('SidebarUtils', () => { lastAction: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, isReportArchived: true, lastActionReport: undefined, @@ -2745,6 +2774,7 @@ describe('SidebarUtils', () => { lastAction: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastActionReport: undefined, isReportArchived: undefined, @@ -2888,6 +2918,7 @@ describe('SidebarUtils', () => { lastAction: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastActionReport: undefined, isReportArchived: undefined, @@ -2940,6 +2971,7 @@ describe('SidebarUtils', () => { lastAction: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastActionReport: undefined, isReportArchived: undefined, @@ -3017,6 +3049,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -3084,6 +3117,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -3141,6 +3175,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: undefined, lastActionReport: undefined, @@ -3236,6 +3271,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -3367,6 +3403,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -3460,6 +3497,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -3565,6 +3603,7 @@ describe('SidebarUtils', () => { lastAction: lastReportPreviewAction, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastActionReport: undefined, isReportArchived: undefined, @@ -3681,6 +3720,7 @@ describe('SidebarUtils', () => { lastAction: lastReportPreviewAction, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastActionReport: undefined, isReportArchived: undefined, @@ -3727,6 +3767,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: undefined, lastActionReport: undefined, @@ -3762,6 +3803,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: undefined, lastActionReport: undefined, @@ -3796,6 +3838,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction: undefined, lastActionReport: undefined, @@ -3848,6 +3891,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, @@ -4649,6 +4693,7 @@ describe('SidebarUtils', () => { card: undefined, translate: translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, localeCompare, lastAction, lastActionReport: undefined, diff --git a/tests/unit/hooks/useAutocompleteSuggestions.test.ts b/tests/unit/hooks/useAutocompleteSuggestions.test.ts index 35440395f6e5..470f30e6be2d 100644 --- a/tests/unit/hooks/useAutocompleteSuggestions.test.ts +++ b/tests/unit/hooks/useAutocompleteSuggestions.test.ts @@ -24,6 +24,7 @@ jest.mock('@hooks/useOnyx', () => ({ jest.mock('@hooks/useNetwork', () => jest.fn(() => ({isOffline: false}))); jest.mock('@libs/actions/Search', () => ({openSearchCategoryFiltersPage: jest.fn()})); +const mockConvertToDisplayString = jest.fn(() => '$0.00'); jest.mock('@hooks/useCurrencyList', () => ({ useCurrencyListState: () => ({ currencyList: { @@ -35,6 +36,7 @@ jest.mock('@hooks/useCurrencyList', () => ({ RETIRED_CURRENCY: {symbol: 'X', name: 'Retired', retired: true}, }, }), + useCurrencyListActions: () => ({convertToDisplayString: mockConvertToDisplayString}), })); jest.mock('@libs/SearchAutocompleteUtils', () => ({ diff --git a/tests/unit/hooks/useMoneyRequestParticipantsPolicyTags.test.ts b/tests/unit/hooks/useMoneyRequestParticipantsPolicyTags.test.ts index 18447a9eb923..4f8a8db09985 100644 --- a/tests/unit/hooks/useMoneyRequestParticipantsPolicyTags.test.ts +++ b/tests/unit/hooks/useMoneyRequestParticipantsPolicyTags.test.ts @@ -16,6 +16,11 @@ jest.mock('@libs/actions/IOU/MoneyRequest', () => ({ getMoneyRequestParticipantOptions: jest.fn(), })); +const mockConvertToDisplayString = jest.fn(() => '$0.00'); +jest.mock('@hooks/useCurrencyList', () => ({ + useCurrencyListActions: () => ({convertToDisplayString: mockConvertToDisplayString}), +})); + const translate = jest.fn().mockReturnValue('translated'); describe('useMoneyRequestParticipantsPolicyTags', () => { @@ -56,7 +61,19 @@ describe('useMoneyRequestParticipantsPolicyTags', () => { await waitFor(() => expect(result.current.participants).toEqual(mockParticipants)); - expect(getMoneyRequestParticipantOptions).toHaveBeenCalledWith(999, report, policy, personalDetails, 'concierge1', false, reportAttributesDerived, reportDraft, translate, undefined); + expect(getMoneyRequestParticipantOptions).toHaveBeenCalledWith({ + currentUserAccountID: 999, + report, + policy, + personalDetails, + conciergeReportID: 'concierge1', + privateIsArchived: false, + reportAttributesDerived, + reportDraft, + translate, + convertToDisplayString: mockConvertToDisplayString, + dateFnsLocale: undefined, + }); }); it('derives participantsPolicyTags from Onyx policy tags keyed by each participant policyID', async () => { diff --git a/tests/unit/reportAttributesTest.ts b/tests/unit/reportAttributesTest.ts index a898e705e07f..a5fa3f78d890 100644 --- a/tests/unit/reportAttributesTest.ts +++ b/tests/unit/reportAttributesTest.ts @@ -283,6 +283,7 @@ describe('reportAttributes compute — policy change code flow', () => { undefined, // conciergeReportID undefined, // introSelected undefined, // reportMetadata + undefined, // currencyList undefined, // network ]; return args; diff --git a/tests/unit/useCurrencyListTest.tsx b/tests/unit/useCurrencyListTest.tsx new file mode 100644 index 000000000000..4fa26b1216f2 --- /dev/null +++ b/tests/unit/useCurrencyListTest.tsx @@ -0,0 +1,129 @@ +import {renderHook} from '@testing-library/react-native'; + +import ComposeProviders from '@components/ComposeProviders'; +import {CurrencyListContextProvider} from '@components/CurrencyListContextProvider'; +import {LocaleContextProvider} from '@components/LocaleContextProvider'; +import OnyxListItemProvider from '@components/OnyxListItemProvider'; + +import {useCurrencyListActions} from '@hooks/useCurrencyList'; + +import CONST from '@src/CONST'; +import IntlStore from '@src/languages/IntlStore'; +import ONYXKEYS from '@src/ONYXKEYS'; + +import React from 'react'; +import Onyx from 'react-native-onyx'; + +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; +import currencyList from './currencyList.json'; + +function Wrapper({children}: {children: React.ReactNode}) { + return {children}; +} + +async function renderCurrencyListActions() { + const hook = renderHook(() => useCurrencyListActions(), {wrapper: Wrapper}); + await waitForBatchedUpdates(); + return hook; +} + +describe('useCurrencyListActions', () => { + beforeAll(() => { + Onyx.init({ + keys: ONYXKEYS, + initialKeyStates: { + [ONYXKEYS.NVP_PREFERRED_LOCALE]: CONST.LOCALES.DEFAULT, + [ONYXKEYS.CURRENCY_LIST]: currencyList, + }, + }); + return waitForBatchedUpdates(); + }); + + beforeEach(async () => { + await IntlStore.load(CONST.LOCALES.DEFAULT); + await Onyx.merge(ONYXKEYS.NVP_PREFERRED_LOCALE, CONST.LOCALES.DEFAULT); + await Onyx.merge(ONYXKEYS.CURRENCY_LIST, currencyList); + await waitForBatchedUpdates(); + }); + + describe('getCurrencyDecimals', () => { + test('Currency decimals smaller than or equal 2', async () => { + const {result} = await renderCurrencyListActions(); + expect(result.current.getCurrencyDecimals('JPY')).toBe(0); + expect(result.current.getCurrencyDecimals('USD')).toBe(2); + expect(result.current.getCurrencyDecimals('RSD')).toBe(2); + }); + + test('Currency decimals larger than 2 should return 2', async () => { + const {result} = await renderCurrencyListActions(); + + // Actual: 3 + expect(result.current.getCurrencyDecimals('LYD')).toBe(2); + + // Actual: 4 + expect(result.current.getCurrencyDecimals('UYW')).toBe(2); + }); + }); + + describe('convertToDisplayString', () => { + test.each([ + [CONST.CURRENCY.USD, 25, '$0.25'], + [CONST.CURRENCY.USD, 2500, '$25.00'], + [CONST.CURRENCY.USD, 150, '$1.50'], + [CONST.CURRENCY.USD, 250000, '$2,500.00'], + ['JPY', 2500, '¥25'], + ['JPY', 250000, '¥2,500'], + ['JPY', 2500.5, '¥25'], + ['RSD', 100, 'RSD\xa01.00'], + ['RSD', 145, 'RSD\xa01.45'], + ['BHD', 12345, 'BHD\xa0123.45'], + ['BHD', 1, 'BHD\xa00.01'], + ])('Correctly displays %s', async (currency, amount, expectedResult) => { + const {result} = await renderCurrencyListActions(); + expect(result.current.convertToDisplayString(amount, currency)).toBe(expectedResult); + }); + + test.each([ + ['EUR', 25, '0,25\xa0€'], + ['EUR', 2500, '25,00\xa0€'], + ['EUR', 250000, '2500,00\xa0€'], + ['EUR', 250000000, '2.500.000,00\xa0€'], + ])('Correctly displays %s in ES locale', async (currency, amount, expectedResult) => { + await IntlStore.load(CONST.LOCALES.ES); + await Onyx.merge(ONYXKEYS.NVP_PREFERRED_LOCALE, CONST.LOCALES.ES); + await waitForBatchedUpdates(); + + const {result} = await renderCurrencyListActions(); + expect(result.current.convertToDisplayString(amount, currency)).toBe(expectedResult); + }); + }); + + describe('convertToDisplayString with malformed currency', () => { + test.each(['', 'XX', 'USDD', '???'])('does not throw and falls back to USD formatting for %p', async (input) => { + const {result} = await renderCurrencyListActions(); + expect(() => result.current.convertToDisplayString(2500, input)).not.toThrow(); + expect(result.current.convertToDisplayString(2500, input)).toBe('$25.00'); + }); + + test('normalizes case-only variations to the intended currency instead of USD', async () => { + const {result} = await renderCurrencyListActions(); + expect(result.current.convertToDisplayString(2500, 'eur')).toBe(result.current.convertToDisplayString(2500, 'EUR')); + }); + + test('handles undefined currency', async () => { + const {result} = await renderCurrencyListActions(); + expect(result.current.convertToDisplayString(2500, undefined)).toBe('$25.00'); + }); + }); + + describe('convertToDisplayStringWithoutCurrency with malformed currency', () => { + test.each(['', 'XX', 'USDD', '???'])('does not throw and produces a numeric output for %p', async (input) => { + const {result} = await renderCurrencyListActions(); + expect(() => result.current.convertToDisplayStringWithoutCurrency(2500, input)).not.toThrow(); + // Output should not contain a currency symbol but should contain the numeric portion. + const output = result.current.convertToDisplayStringWithoutCurrency(2500, input); + expect(output).not.toMatch(/\$/); + expect(output).toContain('25'); + }); + }); +}); diff --git a/tests/utils/TestHelper.ts b/tests/utils/TestHelper.ts index 9876c8bec45b..675143fec395 100644 --- a/tests/utils/TestHelper.ts +++ b/tests/utils/TestHelper.ts @@ -5,7 +5,7 @@ import {convertToFrontendAmountAsInteger, sanitizeCurrencyCode} from '@libs/Curr import {formatPhoneNumberWithCountryCode} from '@libs/LocalePhoneNumber'; import {translate} from '@libs/Localize'; import registerMiddlewares from '@libs/Middleware/register'; -import {format as formatNumber} from '@libs/NumberFormatUtils'; +import {format as formatNumber, formatToParts} from '@libs/NumberFormatUtils'; import Pusher from '@libs/Pusher'; import PusherConnectionManager from '@libs/PusherConnectionManager'; @@ -509,6 +509,26 @@ function convertToDisplayString(amountInCents: number | undefined, currencyCode: }); } +/** + * A local version of useCurrencyListActions().convertToDisplayStringWithoutCurrency for tests that call lib + * functions directly and need to inject the symbol-less formatter without the full app context. + */ +function convertToDisplayStringWithoutCurrency(amountInCents: number, currencyCode: string = CONST.CURRENCY.USD): string { + const sanitizedCurrency = sanitizeCurrencyCode(currencyCode); + const decimals = getCurrencyDecimalsLocal(sanitizedCurrency); + const convertedAmount = convertToFrontendAmountAsInteger(amountInCents, decimals); + return formatToParts(CONST.LOCALES.EN, convertedAmount, { + style: 'currency', + currency: sanitizedCurrency, + minimumFractionDigits: decimals, + maximumFractionDigits: 2, + }) + .filter((x) => x.type !== 'currency') + .filter((x) => x.type !== 'literal' || x.value.trim().length !== 0) + .map((x) => x.value) + .join(''); +} + function getNavigateToChatHintRegex(): RegExp { const hintTextPrefix = translateLocal('accessibilityHints.navigatesToChat'); return new RegExp(hintTextPrefix, 'i'); @@ -540,6 +560,7 @@ export { anyString, translateLocal, convertToDisplayString, + convertToDisplayStringWithoutCurrency, getCurrencyDecimalsLocal, getCurrencySymbolLocal, assertFormDataMatchesObject,