Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
98ca2cc
fix(LHN): remove brackets from expense amount in preview
marufsharifi Apr 1, 2026
6d672f4
add missed translation
marufsharifi Apr 1, 2026
9f0df87
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi Apr 3, 2026
d9dc632
refactor(lhn): extract canonical money request preview helper
marufsharifi Apr 3, 2026
dc64f8b
add unit tests
marufsharifi Apr 3, 2026
f4af4e2
add comment for deprecated sort actions
marufsharifi Apr 3, 2026
fd5b25d
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi Apr 9, 2026
48ca09e
address feedbacks
marufsharifi Apr 9, 2026
8fbb12c
fix eslint
marufsharifi Apr 9, 2026
79b7f7c
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi Apr 14, 2026
672c3f1
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi Apr 14, 2026
68a5857
fix(lhn): preserve sign in expense preview fallback
marufsharifi Apr 15, 2026
f8859a0
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi Apr 15, 2026
6c95c19
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi Apr 21, 2026
837f185
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi May 8, 2026
2e06d1e
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi May 11, 2026
159ec86
skip money-request fallback when only CREATED remains
marufsharifi May 11, 2026
49cf77e
add test for formatting non-expense IOU fallback with requestor name
marufsharifi May 12, 2026
1e7c938
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi May 12, 2026
76b1fc6
fix: preserve IOU preview fallback behavior
marufsharifi May 12, 2026
524f5c5
preserve merchant in expense preview fallback
marufsharifi May 12, 2026
cca0c91
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi May 12, 2026
33ace78
fix: use linked transaction amount in expense preview
marufsharifi May 13, 2026
d3de62b
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi May 13, 2026
95bdb9b
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi May 19, 2026
3779b40
fix: update expense preview to use description instead of merchant
marufsharifi May 19, 2026
04bf251
Merge branch 'main' into fix/lhn-expense-amount-bracket-preview
marufsharifi May 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 57 additions & 10 deletions src/libs/OptionsListUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import FallbackAvatar from '@assets/images/avatars/fallback-avatar.svg';
import type {LocaleContextProps, LocalizedTranslate} from '@components/LocaleContextProvider';
import type {PrivateIsArchivedMap} from '@hooks/usePrivateIsArchivedMap';
import {getEnabledCategoriesCount} from '@libs/CategoryUtils';
import {convertToDisplayString} from '@libs/CurrencyUtils';
import filterArrayByMatch from '@libs/filterArrayByMatch';
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
import {isReportMessageAttachment} from '@libs/isReportMessageAttachment';
Expand Down Expand Up @@ -165,7 +166,7 @@ import {
} from '@libs/ReportUtils';
import StringUtils from '@libs/StringUtils';
import {getTaskCreatedMessage, getTaskReportActionMessage} from '@libs/TaskUtils';
import {isScanning} from '@libs/TransactionUtils';
import {getDescription, getAmount as getTransactionAmount, getCurrency as getTransactionCurrency, isScanning} from '@libs/TransactionUtils';
import {generateAccountID} from '@libs/UserUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
Expand All @@ -185,6 +186,7 @@ import type {
ReportActions,
ReportAttributesDerivedValue,
ReportMetadata,
Transaction,
VisibleReportActionsDerivedValue,
} from '@src/types/onyx';
import type {Attendee, Participant} from '@src/types/onyx/IOU';
Expand Down Expand Up @@ -571,6 +573,43 @@ function hasHiddenDisplayNames(accountIDs: number[]) {
return getPersonalDetailsByIDs({accountIDs, currentUserAccountID: 0}).some((personalDetail) => !getDisplayNameOrDefault(personalDetail, undefined, false));
}

function getLatestVisibleMoneyRequestAction(
reportID: string,
canUserPerformWrite: boolean | undefined,
sortedReportActions: ReportAction[] = [],
visibleReportActionsData?: VisibleReportActionsDerivedValue,
): OnyxEntry<ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU>> {
return sortedReportActions.find(
(reportAction): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU> =>
isMoneyRequestAction(reportAction) &&
reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE &&
isReportActionVisible(reportAction, reportID, canUserPerformWrite, visibleReportActionsData),
);
}

function getExpenseReportPreviewText(
report: OnyxEntry<Report>,
moneyRequestAction: OnyxEntry<ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU>>,
translate: LocalizedTranslate,
transactions: Transaction[] = [],
): string {
const originalMessage = moneyRequestAction ? getOriginalMessage(moneyRequestAction) : undefined;
const linkedTransaction = transactions.find((transaction) => transaction.transactionID === originalMessage?.IOUTransactionID);
const amount = linkedTransaction ? getTransactionAmount(linkedTransaction, true) : originalMessage?.amount;
const currency = linkedTransaction ? getTransactionCurrency(linkedTransaction) : (originalMessage?.currency ?? report?.currency);

if (typeof amount !== 'number' || !currency) {
return '';
}

const formattedAmount = convertToDisplayString(amount, currency);
const description = linkedTransaction ? getDescription(linkedTransaction) : '';
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const comment = Parser.htmlToText(description || originalMessage?.comment || '').trim();

return formatReportLastMessageText(translate('iou.expenseAmount', formattedAmount, comment || undefined));
}

function getLastActorDisplayNameFromLastVisibleActions(
report: OnyxEntry<Report>,
lastActorDetails: Partial<PersonalDetails> | null,
Expand Down Expand Up @@ -713,14 +752,7 @@ function getLastMessageTextForReport({
const iouReportActions = iouReportID ? sortedActions?.[iouReportID] : undefined;
const canPerformWrite = canUserPerformWriteAction(report, isReportArchived);
const lastIOUMoneyReportAction =
iouReportID && iouReportActions
? iouReportActions.find(
(reportAction): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU> =>
isReportActionVisible(reportAction, iouReportID, canPerformWrite, visibleReportActionsForIOUReport) &&
reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE &&
isMoneyRequestAction(reportAction),
)
: undefined;
iouReportID && iouReportActions ? getLatestVisibleMoneyRequestAction(iouReportID, canPerformWrite, iouReportActions, visibleReportActionsForIOUReport) : undefined;

// For workspace chats, use the report title
if (reportUtilsIsPolicyExpenseChat(report) && !isEmptyObject(iouReport)) {
Expand Down Expand Up @@ -969,7 +1001,22 @@ function getLastMessageTextForReport({
if (scanningTransactions.length > 0) {
lastMessageTextFromReport = translate('iou.receiptScanning', {count: scanningTransactions.length});
} else if (report?.transactionCount && report?.transactionCount > 0 && report?.currency) {
lastMessageTextFromReport = lastVisibleMessage?.lastMessageText;
const latestVisibleMoneyRequestAction = getLatestVisibleMoneyRequestAction(
reportID,
canUserPerformWrite,
// eslint-disable-next-line @typescript-eslint/no-deprecated
deprecatedAllSortedReportActions[reportID],
visibleReportActionsDataParam,
);
if (isExpenseReport(report) && latestVisibleMoneyRequestAction) {
lastMessageTextFromReport = getExpenseReportPreviewText(report, latestVisibleMoneyRequestAction, translate, transactions);
} else if (!isExpenseReport(report)) {
lastMessageTextFromReport = lastVisibleMessage?.lastMessageText;
} else if (!isCreatedAction(lastReportAction)) {
lastMessageTextFromReport =
formatReportLastMessageText(Parser.htmlToText(getReportPreviewMessage(report, conciergeReportID, lastReportAction, true, false, null, true))) ||
lastVisibleMessage?.lastMessageText;
}
} else if (report?.transactionCount === 0) {
lastMessageTextFromReport = translate('report.noActivityYet');
}
Expand Down
Loading
Loading