From d64c058e7ead3b0601550495df2d0a12a3622a8e Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Fri, 13 Mar 2026 16:34:49 +0700
Subject: [PATCH 01/21] feat: Display Per-Person Amount and Attendees in
 Expense Table

---
 src/CONST/index.ts                            |  6 ++
 .../SearchTableHeader.tsx                     |  8 +++
 src/components/TransactionItemRow/index.tsx   | 64 +++++++++++++++++++
 src/languages/de.ts                           |  1 +
 src/languages/en.ts                           |  1 +
 src/languages/es.ts                           |  1 +
 src/languages/fr.ts                           |  1 +
 src/languages/it.ts                           |  1 +
 src/languages/ja.ts                           |  1 +
 src/languages/nl.ts                           |  1 +
 src/languages/pl.ts                           |  1 +
 src/languages/pt-BR.ts                        |  1 +
 src/languages/zh-hans.ts                      |  1 +
 src/libs/SearchUIUtils.ts                     |  8 +++
 src/styles/utils/index.ts                     |  1 +
 15 files changed, 97 insertions(+)

diff --git a/src/CONST/index.ts b/src/CONST/index.ts
index aa699de640f1..7d1829d9c7e5 100644
--- a/src/CONST/index.ts
+++ b/src/CONST/index.ts
@@ -7294,6 +7294,8 @@ const CONST = {
                     POLICY_NAME: this.TABLE_COLUMNS.POLICY_NAME,
                     CARD: this.TABLE_COLUMNS.CARD,
                     CATEGORY: this.TABLE_COLUMNS.CATEGORY,
+                    ATTENDEES: this.TABLE_COLUMNS.ATTENDEES,
+                    TOTAL_PER_ATTENDEE: this.TABLE_COLUMNS.TOTAL_PER_ATTENDEE,
                     TAG: this.TABLE_COLUMNS.TAG,
                     EXCHANGE_RATE: this.TABLE_COLUMNS.EXCHANGE_RATE,
                     ORIGINAL_AMOUNT: this.TABLE_COLUMNS.ORIGINAL_AMOUNT,
@@ -7418,6 +7420,8 @@ const CONST = {
                     this.TABLE_COLUMNS.FROM,
                     this.TABLE_COLUMNS.TO,
                     this.TABLE_COLUMNS.CATEGORY,
+                    this.TABLE_COLUMNS.ATTENDEES,
+                    this.TABLE_COLUMNS.TOTAL_PER_ATTENDEE,
                     this.TABLE_COLUMNS.TAG,
                     this.TABLE_COLUMNS.TOTAL_AMOUNT,
                     this.TABLE_COLUMNS.ACTION,
@@ -7520,6 +7524,8 @@ const CONST = {
             BILLABLE: 'billable',
             TAX_RATE: 'taxrate',
             TOTAL_AMOUNT: 'amount',
+            ATTENDEES: 'attendees',
+            TOTAL_PER_ATTENDEE: 'totalPerAttendee',
             TOTAL: 'total',
             TYPE: 'type',
             ACTION: 'action',
diff --git a/src/components/SelectionListWithSections/SearchTableHeader.tsx b/src/components/SelectionListWithSections/SearchTableHeader.tsx
index 7d05263b54a0..6bfed64da723 100644
--- a/src/components/SelectionListWithSections/SearchTableHeader.tsx
+++ b/src/components/SelectionListWithSections/SearchTableHeader.tsx
@@ -83,6 +83,14 @@ const getExpenseHeaders = (groupBy?: SearchGroupBy): SearchColumnConfig[] => [
         columnName: CONST.SEARCH.TABLE_COLUMNS.CATEGORY,
         translationKey: 'common.category',
     },
+    {
+        columnName: CONST.SEARCH.TABLE_COLUMNS.ATTENDEES,
+        translationKey: 'iou.attendees',
+    },
+    {
+        columnName: CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE,
+        translationKey: 'iou.totalPerAttendee',
+    },
     {
         columnName: CONST.SEARCH.TABLE_COLUMNS.TAG,
         translationKey: 'common.tag',
diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index 13a5de8f1deb..7485e280a096 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -6,6 +6,7 @@ import Icon from '@components/Icon';
 import type {TransactionWithOptionalHighlight} from '@components/MoneyRequestReportView/MoneyRequestReportTransactionList';
 import {PressableWithFeedback} from '@components/Pressable';
 import RadioButton from '@components/RadioButton';
+import ReportActionAvatars from '@components/ReportActionAvatars';
 import type {SearchColumnType, TableColumnSize} from '@components/Search/types';
 import ActionCell from '@components/SelectionListWithSections/Search/ActionCell';
 import DateCell from '@components/SelectionListWithSections/Search/DateCell';
@@ -16,6 +17,7 @@ import AmountCell from '@components/SelectionListWithSections/Search/TotalCell';
 import UserInfoCell from '@components/SelectionListWithSections/Search/UserInfoCell';
 import WorkspaceCell from '@components/SelectionListWithSections/Search/WorkspaceCell';
 import Text from '@components/Text';
+import TextWithTooltip from '@components/TextWithTooltip';
 import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
 import useLocalize from '@hooks/useLocalize';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
@@ -23,12 +25,16 @@ import useStyleUtils from '@hooks/useStyleUtils';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
 import {isCategoryMissing} from '@libs/CategoryUtils';
+import {convertToDisplayString} from '@libs/CurrencyUtils';
 import getBase62ReportID from '@libs/getBase62ReportID';
+import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils';
 import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils';
 import {getReportName} from '@libs/ReportNameUtils';
 import {isExpenseReport, isIOUReport, isSettled} from '@libs/ReportUtils';
 import StringUtils from '@libs/StringUtils';
 import {
+    getAmount,
+    getCurrency,
     getDescription,
     getExchangeRate,
     getMerchant,
@@ -266,6 +272,30 @@ function TransactionItemRow({
         return transactionItem.cardName;
     }, [transactionItem.cardID, transactionItem.cardName, transactionItem.isCardFeedDeleted, customCardNames, translate]);
 
+    const attendeeAccountIDs = useMemo(
+        () =>
+            transactionItem.comment?.attendees
+                ?.map((attendee) => {
+                    if (attendee.accountID) {
+                        return attendee.accountID;
+                    }
+                    return getPersonalDetailByEmail(attendee.email)?.accountID;
+                })
+                .filter((accountID): accountID is number => typeof accountID === 'number') ?? [],
+        [transactionItem.comment?.attendees],
+    );
+
+    const totalPerAttendee = useMemo(() => {
+        const attendeesCount = transactionItem.comment?.attendees?.length ?? 0;
+        const totalAmount = getAmount(transactionItem);
+
+        if (!attendeesCount || totalAmount === undefined) {
+            return undefined;
+        }
+
+        return totalAmount / attendeesCount;
+    }, [transactionItem]);
+
     const renderColumn = (column: SearchColumnType): React.ReactNode => {
         switch (column) {
             case CONST.SEARCH.TABLE_COLUMNS.TYPE:
@@ -495,6 +525,24 @@ function TransactionItemRow({
                         <TextCell text={cardName} />
                     </View>
                 );
+            case CONST.SEARCH.TABLE_COLUMNS.ATTENDEES:
+                return (
+                    <View
+                        key={column}
+                        style={[StyleUtils.getReportTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.ATTENDEES)]}
+                    >
+                        {!!attendeeAccountIDs.length && (
+                            <ReportActionAvatars
+                                accountIDs={attendeeAccountIDs}
+                                horizontalStacking={{
+                                    sort: CONST.REPORT_ACTION_AVATARS.SORT_BY.ID,
+                                    useCardBG: true,
+                                }}
+                                size={CONST.AVATAR_SIZE.SUBSCRIPT}
+                            />
+                        )}
+                    </View>
+                );
             case CONST.SEARCH.TABLE_COLUMNS.COMMENTS:
                 return (
                     <View
@@ -529,6 +577,22 @@ function TransactionItemRow({
                         />
                     </View>
                 );
+            case CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE:
+                return (
+                    <View
+                        key={column}
+                        style={[StyleUtils.getReportTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE, undefined, isAmountColumnWide)]}
+                    >
+                        {!!totalPerAttendee && (
+                            <TextWithTooltip
+                                testID="TotalPerAttendeeCell"
+                                shouldShowTooltip
+                                text={convertToDisplayString(totalPerAttendee, getCurrency(transactionItem))}
+                                style={[styles.optionDisplayName, styles.pre, styles.justifyContentCenter, styles.textBold, styles.textAlignRight, styles.fontWeightNormal]}
+                            />
+                        )}
+                    </View>
+                );
             case CONST.SEARCH.TABLE_COLUMNS.ORIGINAL_AMOUNT:
                 return (
                     <View
diff --git a/src/languages/de.ts b/src/languages/de.ts
index ac5090cf337a..5b4630e7d344 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -1540,6 +1540,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Diese Buchung ist archiviert',
         bookingArchivedDescription: 'Diese Buchung ist archiviert, weil das Reisedatum verstrichen ist. Füge bei Bedarf eine Ausgabe für den endgültigen Betrag hinzu.',
         attendees: 'Teilnehmende',
+        totalPerAttendee: 'Summe pro Teilnehmendem',
         whoIsYourAccountant: 'Wer ist Ihre Steuerberaterin bzw. Ihr Steuerberater?',
         paymentComplete: 'Zahlung abgeschlossen',
         time: 'Zeit',
diff --git a/src/languages/en.ts b/src/languages/en.ts
index 2f7e97db1d28..03d2b63e71a6 100644
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -1570,6 +1570,7 @@ const translations = {
         bookingArchived: 'This booking is archived',
         bookingArchivedDescription: 'This booking is archived because the trip date has passed. Add an expense for the final amount if needed.',
         attendees: 'Attendees',
+        totalPerAttendee: 'Total per attendee',
         whoIsYourAccountant: 'Who is your accountant?',
         paymentComplete: 'Payment complete',
         time: 'Time',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index be67749dfcd5..71450ee94feb 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1411,6 +1411,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Esta reserva está archivada',
         bookingArchivedDescription: 'Esta reserva está archivada porque la fecha del viaje ha pasado. Agregue un gasto por el monto final si es necesario.',
         attendees: 'Asistentes',
+        totalPerAttendee: 'Total por asistente',
         whoIsYourAccountant: '¿Quién es tu contador?',
         paymentComplete: 'Pago completo',
         time: 'Tiempo',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 3a34c0c1947c..92bd4c4660ea 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -1544,6 +1544,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Cette réservation est archivée',
         bookingArchivedDescription: 'Cette réservation est archivée car la date du voyage est passée. Ajoutez une dépense pour le montant final si nécessaire.',
         attendees: 'Participants',
+        totalPerAttendee: 'Total par participant',
         whoIsYourAccountant: 'Qui est votre comptable ?',
         paymentComplete: 'Paiement terminé',
         time: 'Heure',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index e65e7db28213..68e747b3574e 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -1537,6 +1537,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Questa prenotazione è archiviata',
         bookingArchivedDescription: 'Questa prenotazione è archiviata perché la data del viaggio è passata. Aggiungi una spesa per l’importo finale, se necessario.',
         attendees: 'Partecipanti',
+        totalPerAttendee: 'Totale per partecipante',
         whoIsYourAccountant: 'Chi è il tuo commercialista?',
         paymentComplete: 'Pagamento completato',
         time: 'Ora',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 9ab90d2d8dd3..c81a2bea4673 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -1527,6 +1527,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'この予約はアーカイブされています',
         bookingArchivedDescription: 'この予約は旅行日が過ぎたためアーカイブされています。必要に応じて、最終金額の経費を追加してください。',
         attendees: '参加者',
+        totalPerAttendee: '参加者一人あたりの合計',
         whoIsYourAccountant: 'あなたの会計士は誰ですか？',
         paymentComplete: '支払いが完了しました',
         time: '時間',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 1ade218c60df..7018c8b2237e 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -1535,6 +1535,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Deze boeking is gearchiveerd',
         bookingArchivedDescription: 'Deze boeking is gearchiveerd omdat de reisdatum is verstreken. Voeg indien nodig een uitgave toe voor het eindbedrag.',
         attendees: 'Deelnemers',
+        totalPerAttendee: 'Totaal per deelnemer',
         whoIsYourAccountant: 'Wie is jouw accountant?',
         paymentComplete: 'Betaling voltooid',
         time: 'Tijd',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index dea6dcd3a6ea..2d57906f02cd 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -1534,6 +1534,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Ta rezerwacja jest zarchiwizowana',
         bookingArchivedDescription: 'Ta rezerwacja została zarchiwizowana, ponieważ data podróży już minęła. W razie potrzeby dodaj wydatek na ostateczną kwotę.',
         attendees: 'Uczestnicy',
+        totalPerAttendee: 'Suma na uczestnika',
         whoIsYourAccountant: 'Kim jest twój księgowy?',
         paymentComplete: 'Płatność zakończona',
         time: 'Czas',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index be11c98aa086..037884c4267b 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -1532,6 +1532,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Esta reserva está arquivada',
         bookingArchivedDescription: 'Esta reserva está arquivada porque a data da viagem já passou. Adicione uma despesa com o valor final, se necessário.',
         attendees: 'Participantes',
+        totalPerAttendee: 'Total por participante',
         whoIsYourAccountant: 'Quem é seu contador?',
         paymentComplete: 'Pagamento concluído',
         time: 'Hora',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index f87e2bac4758..122a2b3e72dd 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -1502,6 +1502,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: '此预订已归档',
         bookingArchivedDescription: '此预订已归档，因为行程日期已过。如有需要，请为最终金额添加一笔报销。',
         attendees: '参与者',
+        totalPerAttendee: '每位参与者总计',
         whoIsYourAccountant: '你的会计是谁？',
         paymentComplete: '付款完成',
         time: '时间',
diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts
index 31907d214b8e..cc99bcf21fd3 100644
--- a/src/libs/SearchUIUtils.ts
+++ b/src/libs/SearchUIUtils.ts
@@ -3522,6 +3522,10 @@ function getSearchColumnTranslationKey(columnId: SearchCustomColumnIds): Transla
             return 'common.to';
         case CONST.SEARCH.TABLE_COLUMNS.CATEGORY:
             return 'common.category';
+        case CONST.SEARCH.TABLE_COLUMNS.ATTENDEES:
+            return 'iou.attendees';
+        case CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE:
+            return 'iou.totalPerAttendee';
         case CONST.SEARCH.TABLE_COLUMNS.RECEIPT:
             return 'common.receipt';
         case CONST.SEARCH.TABLE_COLUMNS.TAG:
@@ -4308,6 +4312,8 @@ function getColumnsToShow(
               [CONST.SEARCH.TABLE_COLUMNS.MERCHANT]: false,
               [CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION]: false,
               [CONST.SEARCH.TABLE_COLUMNS.CATEGORY]: false,
+              [CONST.SEARCH.TABLE_COLUMNS.ATTENDEES]: true,
+              [CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE]: true,
               [CONST.SEARCH.TABLE_COLUMNS.TAG]: false,
               [CONST.SEARCH.TABLE_COLUMNS.REIMBURSABLE]: shouldShowReimbursableColumn,
               [CONST.SEARCH.TABLE_COLUMNS.BILLABLE]: shouldShowBillableColumn,
@@ -4329,6 +4335,8 @@ function getColumnsToShow(
               [CONST.SEARCH.TABLE_COLUMNS.POLICY_NAME]: false,
               [CONST.SEARCH.TABLE_COLUMNS.CARD]: false,
               [CONST.SEARCH.TABLE_COLUMNS.CATEGORY]: false,
+              [CONST.SEARCH.TABLE_COLUMNS.ATTENDEES]: true,
+              [CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE]: true,
               [CONST.SEARCH.TABLE_COLUMNS.TAG]: false,
               [CONST.SEARCH.TABLE_COLUMNS.REIMBURSABLE]: false,
               [CONST.SEARCH.TABLE_COLUMNS.BILLABLE]: false,
diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts
index 885ad9cc579e..66db2f36562f 100644
--- a/src/styles/utils/index.ts
+++ b/src/styles/utils/index.ts
@@ -1823,6 +1823,7 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({
             case CONST.SEARCH.TABLE_COLUMNS.ORIGINAL_AMOUNT:
             case CONST.SEARCH.TABLE_COLUMNS.TOTAL_AMOUNT:
             case CONST.SEARCH.TABLE_COLUMNS.GROUP_TOTAL:
+            case CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE:
             case CONST.SEARCH.TABLE_COLUMNS.TOTAL:
                 columnWidth = {...getWidthStyle(isAmountColumnWide ? variables.w130 : variables.w96), ...(!shouldRemoveTotalColumnFlex && styles.flex1), ...styles.alignItemsEnd};
                 break;

From c7c84575f8fc4a401ab4bd778d0283d6266fc717 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Mon, 16 Mar 2026 14:43:00 +0700
Subject: [PATCH 02/21] implement hook to get the attendees

---
 src/components/TransactionItemRow/index.tsx | 18 +++----------
 src/hooks/useAccountIDsByEmails.ts          | 29 +++++++++++++++++++++
 2 files changed, 33 insertions(+), 14 deletions(-)
 create mode 100644 src/hooks/useAccountIDsByEmails.ts

diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index 7485e280a096..7adcd6c54c76 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -27,7 +27,6 @@ import useThemeStyles from '@hooks/useThemeStyles';
 import {isCategoryMissing} from '@libs/CategoryUtils';
 import {convertToDisplayString} from '@libs/CurrencyUtils';
 import getBase62ReportID from '@libs/getBase62ReportID';
-import {getPersonalDetailByEmail} from '@libs/PersonalDetailsUtils';
 import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils';
 import {getReportName} from '@libs/ReportNameUtils';
 import {isExpenseReport, isIOUReport, isSettled} from '@libs/ReportUtils';
@@ -51,6 +50,7 @@ import {
     isUnreportedAndHasInvalidDistanceRateTransaction,
 } from '@libs/TransactionUtils';
 import CONST from '@src/CONST';
+import useAccountIDsByEmails from '@src/hooks/useAccountIDsByEmails';
 import type {TranslationPaths} from '@src/languages/types';
 import type {PersonalDetails, Policy, Report, ReportAction, TransactionViolation} from '@src/types/onyx';
 import type {SearchTransactionAction} from '@src/types/onyx/SearchResults';
@@ -272,18 +272,8 @@ function TransactionItemRow({
         return transactionItem.cardName;
     }, [transactionItem.cardID, transactionItem.cardName, transactionItem.isCardFeedDeleted, customCardNames, translate]);
 
-    const attendeeAccountIDs = useMemo(
-        () =>
-            transactionItem.comment?.attendees
-                ?.map((attendee) => {
-                    if (attendee.accountID) {
-                        return attendee.accountID;
-                    }
-                    return getPersonalDetailByEmail(attendee.email)?.accountID;
-                })
-                .filter((accountID): accountID is number => typeof accountID === 'number') ?? [],
-        [transactionItem.comment?.attendees],
-    );
+    const attendeeEmails = useMemo(() => transactionItem.comment?.attendees?.map((attendee) => attendee.email) ?? [], [transactionItem.comment?.attendees]);
+    const attendeeAccountIDs = useAccountIDsByEmails(attendeeEmails);
 
     const totalPerAttendee = useMemo(() => {
         const attendeesCount = transactionItem.comment?.attendees?.length ?? 0;
@@ -531,7 +521,7 @@ function TransactionItemRow({
                         key={column}
                         style={[StyleUtils.getReportTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.ATTENDEES)]}
                     >
-                        {!!attendeeAccountIDs.length && (
+                        {!!attendeeAccountIDs?.length && (
                             <ReportActionAvatars
                                 accountIDs={attendeeAccountIDs}
                                 horizontalStacking={{
diff --git a/src/hooks/useAccountIDsByEmails.ts b/src/hooks/useAccountIDsByEmails.ts
new file mode 100644
index 000000000000..0bbf7a37b0fe
--- /dev/null
+++ b/src/hooks/useAccountIDsByEmails.ts
@@ -0,0 +1,29 @@
+import {useCallback} from 'react';
+import type {OnyxEntry} from 'react-native-onyx';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import type {PersonalDetailsList} from '@src/types/onyx';
+import useOnyx from './useOnyx';
+
+function useAccountIDsByEmails(emails: string[]) {
+    const personalDetailsSelector = useCallback(
+        (personalDetailsList: OnyxEntry<PersonalDetailsList>) => {
+            return Object.values(personalDetailsList ?? {})
+                .filter((personalDetail) => !!personalDetail?.login && emails.includes(personalDetail.login))
+                .map((personalDetail) => personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID);
+        },
+        [emails],
+    );
+
+    const [accountIDs] = useOnyx(
+        ONYXKEYS.PERSONAL_DETAILS_LIST,
+        {
+            selector: personalDetailsSelector,
+        },
+        [personalDetailsSelector],
+    );
+
+    return accountIDs;
+}
+
+export default useAccountIDsByEmails;

From c2ef12aba541e7b8d5a124de8c2a2a1982db8e81 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Mon, 16 Mar 2026 14:46:39 +0700
Subject: [PATCH 03/21] use getAttendees util

---
 src/components/TransactionItemRow/index.tsx | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index 7adcd6c54c76..fd2fe3b0ffa3 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -33,6 +33,7 @@ import {isExpenseReport, isIOUReport, isSettled} from '@libs/ReportUtils';
 import StringUtils from '@libs/StringUtils';
 import {
     getAmount,
+    getAttendees,
     getCurrency,
     getDescription,
     getExchangeRate,
@@ -272,11 +273,13 @@ function TransactionItemRow({
         return transactionItem.cardName;
     }, [transactionItem.cardID, transactionItem.cardName, transactionItem.isCardFeedDeleted, customCardNames, translate]);
 
-    const attendeeEmails = useMemo(() => transactionItem.comment?.attendees?.map((attendee) => attendee.email) ?? [], [transactionItem.comment?.attendees]);
+    const transactionAttendees = useMemo(() => getAttendees(transactionItem, undefined), [transactionItem]);
+
+    const attendeeEmails = useMemo(() => transactionAttendees?.map((attendee) => attendee.email) ?? [], [transactionAttendees]);
     const attendeeAccountIDs = useAccountIDsByEmails(attendeeEmails);
 
     const totalPerAttendee = useMemo(() => {
-        const attendeesCount = transactionItem.comment?.attendees?.length ?? 0;
+        const attendeesCount = transactionAttendees.length ?? 0;
         const totalAmount = getAmount(transactionItem);
 
         if (!attendeesCount || totalAmount === undefined) {
@@ -284,7 +287,7 @@ function TransactionItemRow({
         }
 
         return totalAmount / attendeesCount;
-    }, [transactionItem]);
+    }, [transactionAttendees.length, transactionItem]);
 
     const renderColumn = (column: SearchColumnType): React.ReactNode => {
         switch (column) {

From c7ac28c7ca1570dea5c95f5b2a38c53d0f4e070e Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Mon, 16 Mar 2026 22:36:32 +0700
Subject: [PATCH 04/21] use avatar from attendee data to display the avatar

---
 src/components/ReportActionAvatars/index.tsx | 17 ++++++++++-
 src/components/TransactionItemRow/index.tsx  | 30 ++++++++++++++------
 src/hooks/useAccountIDsByEmails.ts           | 29 -------------------
 3 files changed, 38 insertions(+), 38 deletions(-)
 delete mode 100644 src/hooks/useAccountIDsByEmails.ts

diff --git a/src/components/ReportActionAvatars/index.tsx b/src/components/ReportActionAvatars/index.tsx
index 5f49c30b4c40..51375346949f 100644
--- a/src/components/ReportActionAvatars/index.tsx
+++ b/src/components/ReportActionAvatars/index.tsx
@@ -7,6 +7,7 @@ import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import type {InvitedEmailsToAccountIDs, Policy, Report, ReportAction} from '@src/types/onyx';
 import type {CardFeed} from '@src/types/onyx/CardFeeds';
+import type {Icon as IconType} from '@src/types/onyx/OnyxCommon';
 import type {HorizontalStacking} from './ReportActionAvatar';
 import ReportActionAvatar from './ReportActionAvatar';
 import useReportActionAvatars from './useReportActionAvatars';
@@ -73,6 +74,12 @@ type ReportActionAvatarsProps = {
 
     /** chatReportID needed for the avatars logic. When provided, this will be used as a fallback if the snapshot is undefined */
     chatReportID?: string;
+
+    /** Custom avatars to display instead of the avatars from the hook */
+    customAvatars?: IconType[];
+
+    /** Custom avatar type to display instead of the avatar type from the hook */
+    customAvatarType?: ValueOf<typeof CONST.REPORT_ACTION_AVATARS.TYPE>;
 };
 
 /**
@@ -106,6 +113,8 @@ function ReportActionAvatars({
     invitedEmailsToAccountIDs,
     shouldUseCustomFallbackAvatar = false,
     chatReportID,
+    customAvatars,
+    customAvatarType,
 }: ReportActionAvatarsProps) {
     const accountIDs = passedAccountIDs.filter((accountID) => accountID !== CONST.DEFAULT_NUMBER_ID);
 
@@ -126,7 +135,7 @@ function ReportActionAvatars({
 
     const {
         avatarType: notPreciseAvatarType,
-        avatars: icons,
+        avatars,
         details: {delegateAccountID},
         source,
     } = useReportActionAvatars({
@@ -143,6 +152,8 @@ function ReportActionAvatars({
         chatReportID,
     });
 
+    const icons = customAvatars ?? avatars;
+
     let avatarType: ValueOf<typeof CONST.REPORT_ACTION_AVATARS.TYPE> = notPreciseAvatarType;
 
     if (avatarType === CONST.REPORT_ACTION_AVATARS.TYPE.MULTIPLE && !icons.length) {
@@ -153,6 +164,10 @@ function ReportActionAvatars({
         avatarType = shouldStackHorizontally ? CONST.REPORT_ACTION_AVATARS.TYPE.MULTIPLE_HORIZONTAL : CONST.REPORT_ACTION_AVATARS.TYPE.MULTIPLE_DIAGONAL;
     }
 
+    if (customAvatarType) {
+        avatarType = customAvatarType;
+    }
+
     const [primaryAvatar, secondaryAvatar] = icons;
 
     if (avatarType === CONST.REPORT_ACTION_AVATARS.TYPE.SUBSCRIPT && (!!secondaryAvatar?.name || !!subscriptCardFeed)) {
diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index fd2fe3b0ffa3..8c3eb0db515a 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -18,6 +18,8 @@ import UserInfoCell from '@components/SelectionListWithSections/Search/UserInfoC
 import WorkspaceCell from '@components/SelectionListWithSections/Search/WorkspaceCell';
 import Text from '@components/Text';
 import TextWithTooltip from '@components/TextWithTooltip';
+import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
+import useDefaultAvatars from '@hooks/useDefaultAvatars';
 import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
 import useLocalize from '@hooks/useLocalize';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
@@ -50,10 +52,11 @@ import {
     isTimeRequest,
     isUnreportedAndHasInvalidDistanceRateTransaction,
 } from '@libs/TransactionUtils';
+import {getDefaultAvatar} from '@libs/UserAvatarUtils';
 import CONST from '@src/CONST';
-import useAccountIDsByEmails from '@src/hooks/useAccountIDsByEmails';
 import type {TranslationPaths} from '@src/languages/types';
 import type {PersonalDetails, Policy, Report, ReportAction, TransactionViolation} from '@src/types/onyx';
+import type {Icon as IconType} from '@src/types/onyx/OnyxCommon';
 import type {SearchTransactionAction} from '@src/types/onyx/SearchResults';
 import CategoryCell from './DataCells/CategoryCell';
 import ChatBubbleCell from './DataCells/ChatBubbleCell';
@@ -208,6 +211,8 @@ function TransactionItemRow({
     const hasCategoryOrTag = !isCategoryMissing(transactionItem?.category) || !!transactionItem.tag;
     const createdAt = getTransactionCreated(transactionItem);
     const expensicons = useMemoizedLazyExpensifyIcons(['ArrowRight']);
+    const currentUserPersonalDetails = useCurrentUserPersonalDetails();
+    const defaultAvatars = useDefaultAvatars();
     const transactionThreadReportID = reportActions ? getIOUActionForTransactionID(reportActions, transactionItem.transactionID)?.childReportID : undefined;
 
     const isDateColumnWide = dateColumnSize === CONST.SEARCH.TABLE_COLUMN_SIZES.WIDE;
@@ -273,10 +278,18 @@ function TransactionItemRow({
         return transactionItem.cardName;
     }, [transactionItem.cardID, transactionItem.cardName, transactionItem.isCardFeedDeleted, customCardNames, translate]);
 
-    const transactionAttendees = useMemo(() => getAttendees(transactionItem, undefined), [transactionItem]);
-
-    const attendeeEmails = useMemo(() => transactionAttendees?.map((attendee) => attendee.email) ?? [], [transactionAttendees]);
-    const attendeeAccountIDs = useAccountIDsByEmails(attendeeEmails);
+    const transactionAttendees = useMemo(() => getAttendees(transactionItem, currentUserPersonalDetails), [transactionItem, currentUserPersonalDetails]);
+
+    const attendeeIcons: IconType[] = useMemo(
+        () =>
+            transactionAttendees.map((attendee) => ({
+                id: attendee.accountID ?? CONST.DEFAULT_NUMBER_ID,
+                name: attendee.displayName ?? attendee.email,
+                source: (attendee.avatarUrl || getDefaultAvatar({accountID: attendee.accountID, defaultAvatars})) ?? '',
+                type: CONST.ICON_TYPE_AVATAR,
+            })),
+        [defaultAvatars, transactionAttendees],
+    );
 
     const totalPerAttendee = useMemo(() => {
         const attendeesCount = transactionAttendees.length ?? 0;
@@ -524,11 +537,12 @@ function TransactionItemRow({
                         key={column}
                         style={[StyleUtils.getReportTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.ATTENDEES)]}
                     >
-                        {!!attendeeAccountIDs?.length && (
+                        {!!attendeeIcons.length && (
                             <ReportActionAvatars
-                                accountIDs={attendeeAccountIDs}
+                                customAvatars={attendeeIcons}
+                                customAvatarType={CONST.REPORT_ACTION_AVATARS.TYPE.MULTIPLE_HORIZONTAL}
                                 horizontalStacking={{
-                                    sort: CONST.REPORT_ACTION_AVATARS.SORT_BY.ID,
+                                    sort: CONST.REPORT_ACTION_AVATARS.SORT_BY.NAME,
                                     useCardBG: true,
                                 }}
                                 size={CONST.AVATAR_SIZE.SUBSCRIPT}
diff --git a/src/hooks/useAccountIDsByEmails.ts b/src/hooks/useAccountIDsByEmails.ts
deleted file mode 100644
index 0bbf7a37b0fe..000000000000
--- a/src/hooks/useAccountIDsByEmails.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import {useCallback} from 'react';
-import type {OnyxEntry} from 'react-native-onyx';
-import CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
-import type {PersonalDetailsList} from '@src/types/onyx';
-import useOnyx from './useOnyx';
-
-function useAccountIDsByEmails(emails: string[]) {
-    const personalDetailsSelector = useCallback(
-        (personalDetailsList: OnyxEntry<PersonalDetailsList>) => {
-            return Object.values(personalDetailsList ?? {})
-                .filter((personalDetail) => !!personalDetail?.login && emails.includes(personalDetail.login))
-                .map((personalDetail) => personalDetail?.accountID ?? CONST.DEFAULT_NUMBER_ID);
-        },
-        [emails],
-    );
-
-    const [accountIDs] = useOnyx(
-        ONYXKEYS.PERSONAL_DETAILS_LIST,
-        {
-            selector: personalDetailsSelector,
-        },
-        [personalDetailsSelector],
-    );
-
-    return accountIDs;
-}
-
-export default useAccountIDsByEmails;

From 21c7142ee41a11f03c7ec924cba9697dae807e05 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Mon, 16 Mar 2026 22:41:35 +0700
Subject: [PATCH 05/21] change condition to display total per attendee

---
 src/components/TransactionItemRow/index.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index 8c3eb0db515a..4c0f21ccf2f9 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -590,7 +590,7 @@ function TransactionItemRow({
                         key={column}
                         style={[StyleUtils.getReportTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE, undefined, isAmountColumnWide)]}
                     >
-                        {!!totalPerAttendee && (
+                        {!!attendeeIcons.length && (
                             <TextWithTooltip
                                 testID="TotalPerAttendeeCell"
                                 shouldShowTooltip

From 8c93a955887fc11d140ed30bfa66a2521e6f9acf Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Tue, 17 Mar 2026 16:21:03 +0700
Subject: [PATCH 06/21] update border color and text style

---
 .../ReportActionAvatars/ReportActionAvatar.tsx     | 14 ++++++++++++--
 src/components/TransactionItemRow/index.tsx        |  5 +++++
 src/styles/utils/index.ts                          |  5 +++++
 3 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/src/components/ReportActionAvatars/ReportActionAvatar.tsx b/src/components/ReportActionAvatars/ReportActionAvatar.tsx
index aad0061dfbc0..2f5c7db25b9d 100644
--- a/src/components/ReportActionAvatars/ReportActionAvatar.tsx
+++ b/src/components/ReportActionAvatars/ReportActionAvatar.tsx
@@ -1,6 +1,6 @@
 import lodashSortBy from 'lodash/sortBy';
 import React, {useMemo} from 'react';
-import type {ColorValue, ImageStyle, StyleProp, ViewStyle} from 'react-native';
+import type {ColorValue, ImageStyle, StyleProp, TextStyle, ViewStyle} from 'react-native';
 import {View} from 'react-native';
 import type {ValueOf} from 'type-fest';
 import type {UpperCaseCharacters} from 'type-fest/source/internal';
@@ -55,6 +55,12 @@ type HorizontalStacking = Partial<{
 
     /** Prop to sort the avatars */
     sort: SortingOptions | SortingOptions[];
+
+    /** Border color for the active avatar */
+    pressedBorderColor?: string;
+
+    /** Inner text style */
+    textStyle?: TextStyle;
 }>;
 
 type AvatarStyles = {
@@ -308,6 +314,8 @@ function ReportActionAvatarMultipleHorizontal({
     useProfileNavigationWrapper,
     fallbackDisplayName,
     reportID,
+    pressedBorderColor,
+    textStyle,
 }: HorizontalStacking & {
     size: ValueOf<typeof CONST.AVATAR_SIZE>;
     shouldShowTooltip: boolean;
@@ -393,6 +401,7 @@ function ReportActionAvatarMultipleHorizontal({
                                     isInReportAction,
                                     shouldUseCardBackground,
                                     isActive,
+                                    customPressedBorderColor: pressedBorderColor,
                                 }),
                                 StyleUtils.getAvatarBorderWidth(size),
                             ]}
@@ -425,6 +434,7 @@ function ReportActionAvatarMultipleHorizontal({
                                 isPressed,
                                 isInReportAction,
                                 shouldUseCardBackground,
+                                customPressedBorderColor: pressedBorderColor,
                             }),
 
                             // Set overlay background color with RGBA value so that the text will not inherit opacity
@@ -435,7 +445,7 @@ function ReportActionAvatarMultipleHorizontal({
                     >
                         <View style={[styles.justifyContentCenter, styles.alignItemsCenter, StyleUtils.getHeight(oneAvatarSize.height), StyleUtils.getWidthStyle(oneAvatarSize.width)]}>
                             <Text
-                                style={[styles.avatarInnerTextSmall, StyleUtils.getAvatarExtraFontSizeStyle(size), styles.userSelectNone]}
+                                style={[styles.avatarInnerTextSmall, StyleUtils.getAvatarExtraFontSizeStyle(size), styles.userSelectNone, textStyle]}
                                 dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
                             >{`+${avatars.length - maxAvatarsInRow}`}</Text>
                         </View>
diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index 4c0f21ccf2f9..7e94e1cbba94 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -544,8 +544,13 @@ function TransactionItemRow({
                                 horizontalStacking={{
                                     sort: CONST.REPORT_ACTION_AVATARS.SORT_BY.NAME,
                                     useCardBG: true,
+                                    isHovered: isHover,
+                                    isPressed: isSelected,
+                                    pressedBorderColor: theme.activeComponentBG,
+                                    textStyle: styles.textMicroBold,
                                 }}
                                 size={CONST.AVATAR_SIZE.SUBSCRIPT}
+                                isInReportAction
                             />
                         )}
                     </View>
diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts
index 31d3b15c0831..0e63bb3de4a9 100644
--- a/src/styles/utils/index.ts
+++ b/src/styles/utils/index.ts
@@ -834,6 +834,7 @@ type AvatarBorderStyleParams = {
     isInReportAction: boolean;
     shouldUseCardBackground: boolean;
     isActive?: boolean;
+    customPressedBorderColor?: string;
 };
 
 function getHorizontalStackedAvatarBorderStyle({
@@ -843,6 +844,7 @@ function getHorizontalStackedAvatarBorderStyle({
     isInReportAction = false,
     shouldUseCardBackground = false,
     isActive = false,
+    customPressedBorderColor,
 }: AvatarBorderStyleParams): ViewStyle {
     let borderColor = shouldUseCardBackground ? theme.cardBG : theme.appBG;
 
@@ -855,6 +857,9 @@ function getHorizontalStackedAvatarBorderStyle({
 
     if (isPressed) {
         borderColor = isInReportAction ? theme.hoverComponentBG : theme.buttonPressedBG;
+        if (customPressedBorderColor) {
+            borderColor = customPressedBorderColor;
+        }
     }
 
     return {borderColor};

From 2e655918dd48bc85c5d0ae1d5378161aa6ed610b Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Wed, 18 Mar 2026 22:05:45 +0700
Subject: [PATCH 07/21] update overlay style and translation

---
 src/components/ReportActionAvatars/ReportActionAvatar.tsx | 7 ++++++-
 src/components/TransactionItemRow/index.tsx               | 5 ++++-
 src/languages/de.ts                                       | 2 +-
 src/languages/en.ts                                       | 2 +-
 src/languages/es.ts                                       | 2 +-
 src/languages/fr.ts                                       | 2 +-
 src/languages/it.ts                                       | 2 +-
 src/languages/ja.ts                                       | 2 +-
 src/languages/nl.ts                                       | 2 +-
 src/languages/pl.ts                                       | 2 +-
 src/languages/pt-BR.ts                                    | 2 +-
 src/languages/zh-hans.ts                                  | 2 +-
 12 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/src/components/ReportActionAvatars/ReportActionAvatar.tsx b/src/components/ReportActionAvatars/ReportActionAvatar.tsx
index 2f5c7db25b9d..02143753c6f2 100644
--- a/src/components/ReportActionAvatars/ReportActionAvatar.tsx
+++ b/src/components/ReportActionAvatars/ReportActionAvatar.tsx
@@ -60,7 +60,10 @@ type HorizontalStacking = Partial<{
     pressedBorderColor?: string;
 
     /** Inner text style */
-    textStyle?: TextStyle;
+    textStyle?: StyleProp<TextStyle>;
+
+    /** Style for the overlay */
+    overlayStyle?: StyleProp<ViewStyle>;
 }>;
 
 type AvatarStyles = {
@@ -316,6 +319,7 @@ function ReportActionAvatarMultipleHorizontal({
     reportID,
     pressedBorderColor,
     textStyle,
+    overlayStyle,
 }: HorizontalStacking & {
     size: ValueOf<typeof CONST.AVATAR_SIZE>;
     shouldShowTooltip: boolean;
@@ -441,6 +445,7 @@ function ReportActionAvatarMultipleHorizontal({
                             StyleUtils.getBackgroundColorWithOpacityStyle(theme.overlay, variables.overlayOpacity),
                             StyleUtils.getHorizontalStackedOverlayAvatarStyle(oneAvatarSize, oneAvatarBorderWidth),
                             icons.at(3)?.type === CONST.ICON_TYPE_WORKSPACE && StyleUtils.getAvatarBorderRadius(size, icons.at(3)?.type),
+                            overlayStyle,
                         ]}
                     >
                         <View style={[styles.justifyContentCenter, styles.alignItemsCenter, StyleUtils.getHeight(oneAvatarSize.height), StyleUtils.getWidthStyle(oneAvatarSize.width)]}>
diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index ec7296eec170..34fc92eaeb66 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -53,6 +53,8 @@ import {
     isUnreportedAndHasInvalidDistanceRateTransaction,
 } from '@libs/TransactionUtils';
 import {getDefaultAvatar} from '@libs/UserAvatarUtils';
+import colors from '@styles/theme/colors';
+import variables from '@styles/variables';
 import CONST from '@src/CONST';
 import type {TranslationPaths} from '@src/languages/types';
 import type {PersonalDetails, Policy, Report, ReportAction, TransactionViolation} from '@src/types/onyx';
@@ -546,7 +548,8 @@ function TransactionItemRow({
                                     isHovered: isHover,
                                     isPressed: isSelected,
                                     pressedBorderColor: theme.activeComponentBG,
-                                    textStyle: styles.textMicroBold,
+                                    textStyle: [styles.textMicroBold, styles.buttonSuccessText],
+                                    overlayStyle: StyleUtils.getBackgroundColorWithOpacityStyle(colors.productDark400, variables.overlayOpacity),
                                 }}
                                 size={CONST.AVATAR_SIZE.SUBSCRIPT}
                                 isInReportAction
diff --git a/src/languages/de.ts b/src/languages/de.ts
index 263ae860e836..6cc07ea33a8a 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -1501,7 +1501,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Diese Buchung ist archiviert',
         bookingArchivedDescription: 'Diese Buchung ist archiviert, weil das Reisedatum verstrichen ist. Füge bei Bedarf eine Ausgabe für den endgültigen Betrag hinzu.',
         attendees: 'Teilnehmende',
-        totalPerAttendee: 'Summe pro Teilnehmendem',
+        totalPerAttendee: 'Betrag pro Teilnehmendem',
         whoIsYourAccountant: 'Wer ist Ihre Steuerberaterin bzw. Ihr Steuerberater?',
         paymentComplete: 'Zahlung abgeschlossen',
         time: 'Zeit',
diff --git a/src/languages/en.ts b/src/languages/en.ts
index 7733eea0d65c..92520463f6ef 100644
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -1536,7 +1536,7 @@ const translations = {
         bookingArchived: 'This booking is archived',
         bookingArchivedDescription: 'This booking is archived because the trip date has passed. Add an expense for the final amount if needed.',
         attendees: 'Attendees',
-        totalPerAttendee: 'Total per attendee',
+        totalPerAttendee: 'Amount per attendee',
         whoIsYourAccountant: 'Who is your accountant?',
         paymentComplete: 'Payment complete',
         time: 'Time',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 05eb847520be..51a798185da1 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1411,7 +1411,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Esta reserva está archivada',
         bookingArchivedDescription: 'Esta reserva está archivada porque la fecha del viaje ha pasado. Agregue un gasto por el monto final si es necesario.',
         attendees: 'Asistentes',
-        totalPerAttendee: 'Total por asistente',
+        totalPerAttendee: 'Monto por asistente',
         whoIsYourAccountant: '¿Quién es tu contador?',
         paymentComplete: 'Pago completo',
         time: 'Tiempo',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 1471fadb44f2..c7517168e4bd 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -1505,7 +1505,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Cette réservation est archivée',
         bookingArchivedDescription: 'Cette réservation est archivée car la date du voyage est passée. Ajoutez une dépense pour le montant final si nécessaire.',
         attendees: 'Participants',
-        totalPerAttendee: 'Total par participant',
+        totalPerAttendee: 'Montant par participant',
         whoIsYourAccountant: 'Qui est votre comptable ?',
         paymentComplete: 'Paiement terminé',
         time: 'Heure',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 0e06b2da5761..ea0a8bf5dd41 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -1500,7 +1500,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Questa prenotazione è archiviata',
         bookingArchivedDescription: 'Questa prenotazione è archiviata perché la data del viaggio è passata. Aggiungi una spesa per l’importo finale, se necessario.',
         attendees: 'Partecipanti',
-        totalPerAttendee: 'Totale per partecipante',
+        totalPerAttendee: 'Importo per partecipante',
         whoIsYourAccountant: 'Chi è il tuo commercialista?',
         paymentComplete: 'Pagamento completato',
         time: 'Ora',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index a4bc67ad26b2..036e98371a35 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -1490,7 +1490,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'この予約はアーカイブされています',
         bookingArchivedDescription: 'この予約は旅行日が過ぎたためアーカイブされています。必要に応じて、最終金額の経費を追加してください。',
         attendees: '参加者',
-        totalPerAttendee: '参加者一人あたりの合計',
+        totalPerAttendee: '参加者一人あたりの金額',
         whoIsYourAccountant: 'あなたの会計士は誰ですか？',
         paymentComplete: '支払いが完了しました',
         time: '時間',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index ff2cebe6e2d5..92c13197822d 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -1497,7 +1497,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Deze boeking is gearchiveerd',
         bookingArchivedDescription: 'Deze boeking is gearchiveerd omdat de reisdatum is verstreken. Voeg indien nodig een uitgave toe voor het eindbedrag.',
         attendees: 'Deelnemers',
-        totalPerAttendee: 'Totaal per deelnemer',
+        totalPerAttendee: 'Bedrag per deelnemer',
         whoIsYourAccountant: 'Wie is jouw accountant?',
         paymentComplete: 'Betaling voltooid',
         time: 'Tijd',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index d967c4eb31db..53658531b146 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -1496,7 +1496,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Ta rezerwacja jest zarchiwizowana',
         bookingArchivedDescription: 'Ta rezerwacja została zarchiwizowana, ponieważ data podróży już minęła. W razie potrzeby dodaj wydatek na ostateczną kwotę.',
         attendees: 'Uczestnicy',
-        totalPerAttendee: 'Suma na uczestnika',
+        totalPerAttendee: 'Kwota na uczestnika',
         whoIsYourAccountant: 'Kim jest twój księgowy?',
         paymentComplete: 'Płatność zakończona',
         time: 'Czas',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 317331994577..33ed998429c4 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -1494,7 +1494,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Esta reserva está arquivada',
         bookingArchivedDescription: 'Esta reserva está arquivada porque a data da viagem já passou. Adicione uma despesa com o valor final, se necessário.',
         attendees: 'Participantes',
-        totalPerAttendee: 'Total por participante',
+        totalPerAttendee: 'Valor por participante',
         whoIsYourAccountant: 'Quem é seu contador?',
         paymentComplete: 'Pagamento concluído',
         time: 'Hora',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 2a2ac5c6c256..4e8d1d6df310 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -1465,7 +1465,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: '此预订已归档',
         bookingArchivedDescription: '此预订已归档，因为行程日期已过。如有需要，请为最终金额添加一笔报销。',
         attendees: '参与者',
-        totalPerAttendee: '每位参与者总计',
+        totalPerAttendee: '每位参与者金额',
         whoIsYourAccountant: '你的会计是谁？',
         paymentComplete: '付款完成',
         time: '时间',

From 6b8f45c9cb8769574a00546700b35944040492f4 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Wed, 18 Mar 2026 23:02:12 +0700
Subject: [PATCH 08/21] update fixed width for attendee column

---
 src/styles/utils/index.ts | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts
index 5cea3024d5f2..eb8623022482 100644
--- a/src/styles/utils/index.ts
+++ b/src/styles/utils/index.ts
@@ -1878,6 +1878,9 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({
             case CONST.SEARCH.TABLE_COLUMNS.EXPORTED_TO:
                 columnWidth = {...getWidthStyle(variables.w72), ...styles.alignItemsCenter};
                 break;
+            case CONST.SEARCH.TABLE_COLUMNS.ATTENDEES:
+                columnWidth = {...getWidthStyle(variables.w72)};
+                break;
             case CONST.SEARCH.TABLE_COLUMNS.GROUP_FEED:
             case CONST.SEARCH.TABLE_COLUMNS.GROUP_BANK_ACCOUNT:
             case CONST.SEARCH.TABLE_COLUMNS.GROUP_WITHDRAWAL_ID:

From ff0857d177e2dda6891e8a3313bff88e2ce5edc8 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Fri, 20 Mar 2026 14:22:32 +0700
Subject: [PATCH 09/21] hide attendee column when the feature is not enalbed

---
 .../MoneyRequestReportTransactionList.tsx     |  19 +--
 src/components/Search/index.tsx               |  13 +-
 .../Search/TransactionGroupListExpanded.tsx   |   8 +-
 src/libs/SearchUIUtils.ts                     |  46 +++++--
 tests/unit/Search/SearchUIUtilsTest.ts        | 129 ++++++++++++++++--
 5 files changed, 178 insertions(+), 37 deletions(-)

diff --git a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx
index 1239c32f21e8..698fa4e8cfa4 100644
--- a/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx
+++ b/src/components/MoneyRequestReportView/MoneyRequestReportTransactionList.tsx
@@ -276,17 +276,18 @@ function MoneyRequestReportTransactionList({
     const isExpenseReportViewFromIOUReport = isIOUReport(report);
     const shouldShowBillableColumn = isBillableEnabledOnPolicy(policy);
     const columnsToShow = useMemo(() => {
-        return getColumnsToShow(
-            currentUserDetails?.accountID,
-            transactions,
-            (reportDetailsColumns ?? []) as SearchCustomColumnIds[],
-            true,
-            undefined,
-            undefined,
+        return getColumnsToShow({
+            currentAccountID: currentUserDetails?.accountID,
+            data: transactions,
+            visibleColumns: (reportDetailsColumns ?? []) as SearchCustomColumnIds[],
+            isExpenseReportView: true,
+            type: undefined,
+            groupBy: undefined,
             isExpenseReportViewFromIOUReport,
             shouldShowBillableColumn,
-            hasNonReimbursableTransactions(transactions),
-        );
+            shouldShowReimbursableColumn: hasNonReimbursableTransactions(transactions),
+            policy,
+        });
     }, [transactions, currentUserDetails?.accountID, isExpenseReportViewFromIOUReport, shouldShowBillableColumn, reportDetailsColumns]);
 
     const {windowWidth, windowHeight} = useWindowDimensions();
diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx
index 0a16220696a3..103f8620499a 100644
--- a/src/components/Search/index.tsx
+++ b/src/components/Search/index.tsx
@@ -1135,7 +1135,18 @@ function Search({
         if (!searchResults?.data) {
             return [];
         }
-        return getColumnsToShow(accountID, searchResults?.data, visibleColumns, false, searchDataType, validGroupBy, false, false, false, shouldUseStrictDefaultExpenseColumns);
+        return getColumnsToShow({
+            currentAccountID: accountID,
+            data: searchResults?.data,
+            visibleColumns,
+            isExpenseReportView: false,
+            type: searchDataType,
+            groupBy: validGroupBy,
+            isExpenseReportViewFromIOUReport: false,
+            shouldShowBillableColumn: false,
+            shouldShowReimbursableColumn: false,
+            shouldUseStrictDefaultExpenseColumns,
+        });
     }, [accountID, searchResults?.data, searchDataType, visibleColumns, validGroupBy, shouldUseStrictDefaultExpenseColumns]);
 
     const opacity = useSharedValue(1);
diff --git a/src/components/SelectionListWithSections/Search/TransactionGroupListExpanded.tsx b/src/components/SelectionListWithSections/Search/TransactionGroupListExpanded.tsx
index 7cb5be7d361d..55792bc54f7c 100644
--- a/src/components/SelectionListWithSections/Search/TransactionGroupListExpanded.tsx
+++ b/src/components/SelectionListWithSections/Search/TransactionGroupListExpanded.tsx
@@ -77,7 +77,13 @@ function TransactionGroupListExpanded<TItem extends ListItem>({
         if (!transactionsSnapshot?.data) {
             currentColumns = [];
         } else {
-            currentColumns = getColumnsToShow(accountID, transactionsSnapshot?.data, visibleColumns, false, transactionsSnapshot?.search.type);
+            currentColumns = getColumnsToShow({
+                currentAccountID: accountID,
+                data: transactionsSnapshot?.data,
+                visibleColumns,
+                isExpenseReportView: false,
+                type: transactionsSnapshot?.search.type,
+            });
         }
     }
 
diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts
index b142da5b21b0..092653cbd74e 100644
--- a/src/libs/SearchUIUtils.ts
+++ b/src/libs/SearchUIUtils.ts
@@ -157,6 +157,7 @@ import {
     isPending,
     isScanning,
     isViolationDismissed,
+    shouldShowAttendees,
 } from './TransactionUtils';
 import {isInvalidMerchantValue} from './ValidationUtils';
 import ViolationsUtils from './Violations/ViolationsUtils';
@@ -4236,18 +4237,31 @@ function getActionOptions(translate: LocaleContextProps['translate']) {
  * @param isExpenseReportView: true when we are inside an expense report view, false if we're in the Reports page.
  * @returns An ordered array of visible column IDs
  */
-function getColumnsToShow(
-    currentAccountID: number | undefined,
-    data: OnyxTypes.SearchResults['data'] | OnyxTypes.Transaction[],
-    visibleColumns: SearchCustomColumnIds[] = [],
+function getColumnsToShow({
+    currentAccountID,
+    data,
+    visibleColumns = [],
     isExpenseReportView = false,
-    type?: SearchDataTypes,
-    groupBy?: SearchGroupBy,
+    type,
+    groupBy,
     isExpenseReportViewFromIOUReport = false,
     shouldShowBillableColumn = false,
     shouldShowReimbursableColumn = false,
     shouldUseStrictDefaultExpenseColumns = false,
-): SearchColumnType[] {
+    policy,
+}: {
+    currentAccountID: number | undefined;
+    data: OnyxTypes.SearchResults['data'] | OnyxTypes.Transaction[];
+    visibleColumns?: SearchCustomColumnIds[];
+    isExpenseReportView?: boolean;
+    type?: SearchDataTypes;
+    groupBy?: SearchGroupBy;
+    isExpenseReportViewFromIOUReport?: boolean;
+    shouldShowBillableColumn?: boolean;
+    shouldShowReimbursableColumn?: boolean;
+    shouldUseStrictDefaultExpenseColumns?: boolean;
+    policy?: OnyxTypes.Policy;
+}): SearchColumnType[] {
     if (type === CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT) {
         const defaultReportColumns: SearchColumnType[] = [
             CONST.SEARCH.TABLE_COLUMNS.AVATAR,
@@ -4355,8 +4369,8 @@ function getColumnsToShow(
               [CONST.SEARCH.TABLE_COLUMNS.MERCHANT]: false,
               [CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION]: false,
               [CONST.SEARCH.TABLE_COLUMNS.CATEGORY]: false,
-              [CONST.SEARCH.TABLE_COLUMNS.ATTENDEES]: true,
-              [CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE]: true,
+              [CONST.SEARCH.TABLE_COLUMNS.ATTENDEES]: false,
+              [CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE]: false,
               [CONST.SEARCH.TABLE_COLUMNS.TAG]: false,
               [CONST.SEARCH.TABLE_COLUMNS.REIMBURSABLE]: shouldShowReimbursableColumn,
               [CONST.SEARCH.TABLE_COLUMNS.BILLABLE]: shouldShowBillableColumn,
@@ -4379,8 +4393,8 @@ function getColumnsToShow(
               [CONST.SEARCH.TABLE_COLUMNS.POLICY_NAME]: false,
               [CONST.SEARCH.TABLE_COLUMNS.CARD]: false,
               [CONST.SEARCH.TABLE_COLUMNS.CATEGORY]: false,
-              [CONST.SEARCH.TABLE_COLUMNS.ATTENDEES]: true,
-              [CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE]: true,
+              [CONST.SEARCH.TABLE_COLUMNS.ATTENDEES]: false,
+              [CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE]: false,
               [CONST.SEARCH.TABLE_COLUMNS.TAG]: false,
               [CONST.SEARCH.TABLE_COLUMNS.REIMBURSABLE]: false,
               [CONST.SEARCH.TABLE_COLUMNS.BILLABLE]: false,
@@ -4489,8 +4503,18 @@ function getColumnsToShow(
         for (const item of data) {
             updateColumns(item);
         }
+        if (shouldShowAttendees(CONST.IOU.TYPE.SUBMIT, policy)) {
+            columns[CONST.SEARCH.TABLE_COLUMNS.ATTENDEES] = true;
+            columns[CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE] = true;
+        }
     } else {
         for (const key of Object.keys(data)) {
+            if (isPolicyEntry(key)) {
+                if (shouldShowAttendees(CONST.IOU.TYPE.SUBMIT, data[key])) {
+                    columns[CONST.SEARCH.TABLE_COLUMNS.ATTENDEES] = true;
+                    columns[CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE] = true;
+                }
+            }
             if (!isTransactionEntry(key)) {
                 continue;
             }
diff --git a/tests/unit/Search/SearchUIUtilsTest.ts b/tests/unit/Search/SearchUIUtilsTest.ts
index 944d1c60a9fe..22f3d30c23e8 100644
--- a/tests/unit/Search/SearchUIUtilsTest.ts
+++ b/tests/unit/Search/SearchUIUtilsTest.ts
@@ -6808,7 +6808,15 @@ describe('SearchUIUtils', () => {
 
     describe('Test getColumnsToShow', () => {
         test('Should show all default columns when no custom columns are saved & viewing expense reports', () => {
-            expect(SearchUIUtils.getColumnsToShow(1, [], [], false, CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT)).toEqual([
+            expect(
+                SearchUIUtils.getColumnsToShow({
+                    currentAccountID: 1,
+                    data: [],
+                    visibleColumns: [],
+                    isExpenseReportView: false,
+                    type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT,
+                }),
+            ).toEqual([
                 CONST.SEARCH.TABLE_COLUMNS.AVATAR,
                 CONST.SEARCH.TABLE_COLUMNS.DATE,
                 CONST.SEARCH.TABLE_COLUMNS.STATUS,
@@ -6823,7 +6831,15 @@ describe('SearchUIUtils', () => {
         test('Should show specific columns when custom columns are saved & viewing expense reports', () => {
             const visibleColumns = [CONST.SEARCH.TABLE_COLUMNS.DATE, CONST.SEARCH.TABLE_COLUMNS.STATUS, CONST.SEARCH.TABLE_COLUMNS.TITLE, CONST.SEARCH.TABLE_COLUMNS.TOTAL];
 
-            expect(SearchUIUtils.getColumnsToShow(1, [], visibleColumns, false, CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT)).toEqual([
+            expect(
+                SearchUIUtils.getColumnsToShow({
+                    currentAccountID: 1,
+                    data: [],
+                    visibleColumns,
+                    isExpenseReportView: false,
+                    type: CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT,
+                }),
+            ).toEqual([
                 // Avatar should always be visible
                 CONST.SEARCH.TABLE_COLUMNS.AVATAR,
                 CONST.SEARCH.TABLE_COLUMNS.DATE,
@@ -6854,12 +6870,34 @@ describe('SearchUIUtils', () => {
                 personalDetailsList: searchResults.data.personalDetailsList,
             };
 
-            const nonStrictColumns = SearchUIUtils.getColumnsToShow(submitterAccountID, data, [], false, undefined, undefined, false, false, false, false);
+            const nonStrictColumns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data,
+                visibleColumns: [],
+                isExpenseReportView: false,
+                type: undefined,
+                groupBy: undefined,
+                isExpenseReportViewFromIOUReport: false,
+                shouldShowBillableColumn: false,
+                shouldShowReimbursableColumn: false,
+                shouldUseStrictDefaultExpenseColumns: false,
+            });
             expect(nonStrictColumns).toContain(CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION);
             expect(nonStrictColumns).toContain(CONST.SEARCH.TABLE_COLUMNS.TAG);
             expect(nonStrictColumns).toContain(CONST.SEARCH.TABLE_COLUMNS.TO);
 
-            const strictColumns = SearchUIUtils.getColumnsToShow(submitterAccountID, data, [], false, undefined, undefined, false, false, false, true);
+            const strictColumns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data,
+                visibleColumns: [],
+                isExpenseReportView: false,
+                type: undefined,
+                groupBy: undefined,
+                isExpenseReportViewFromIOUReport: false,
+                shouldShowBillableColumn: false,
+                shouldShowReimbursableColumn: false,
+                shouldUseStrictDefaultExpenseColumns: true,
+            });
             expect(strictColumns).toContain(CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION);
             expect(strictColumns).toContain(CONST.SEARCH.TABLE_COLUMNS.TAG);
             expect(strictColumns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.TO);
@@ -6948,7 +6986,12 @@ describe('SearchUIUtils', () => {
             };
 
             // Test 1: No optional fields should be shown when all transactions are empty
-            let columns = SearchUIUtils.getColumnsToShow(submitterAccountID, [emptyTransaction, emptyTransaction], [], false);
+            let columns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data: [emptyTransaction, emptyTransaction],
+                visibleColumns: [],
+                isExpenseReportView: false,
+            });
             expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.MERCHANT);
             expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.CATEGORY);
             expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.TAG);
@@ -6957,22 +7000,42 @@ describe('SearchUIUtils', () => {
             expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.TO);
 
             // Test 2: Merchant column should show when at least one transaction has merchant
-            columns = SearchUIUtils.getColumnsToShow(submitterAccountID, [emptyTransaction, merchantTransaction], [], false);
+            columns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data: [emptyTransaction, merchantTransaction],
+                visibleColumns: [],
+                isExpenseReportView: false,
+            });
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.MERCHANT);
             expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.CATEGORY);
 
             // Test 3: Category column should show when at least one transaction has category
-            columns = SearchUIUtils.getColumnsToShow(submitterAccountID, [emptyTransaction, categoryTransaction], [], false);
+            columns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data: [emptyTransaction, categoryTransaction],
+                visibleColumns: [],
+                isExpenseReportView: false,
+            });
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.CATEGORY);
             expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.MERCHANT);
 
             // Test 4: Tag column should show when at least one transaction has tag
-            columns = SearchUIUtils.getColumnsToShow(submitterAccountID, [emptyTransaction, tagTransaction], [], false);
+            columns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data: [emptyTransaction, tagTransaction],
+                visibleColumns: [],
+                isExpenseReportView: false,
+            });
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.TAG);
             expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.CATEGORY);
 
             // Test 5: Description column should show when at least one transaction has description
-            columns = SearchUIUtils.getColumnsToShow(submitterAccountID, [emptyTransaction, descriptionTransaction], [], false);
+            columns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data: [emptyTransaction, descriptionTransaction],
+                visibleColumns: [],
+                isExpenseReportView: false,
+            });
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.DESCRIPTION);
             expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.MERCHANT);
 
@@ -6985,12 +7048,22 @@ describe('SearchUIUtils', () => {
                 [`reportActions_${reportID2}`]: {[differentUsersTransactionIOUAction.reportActionID]: differentUsersTransactionIOUAction},
                 personalDetailsList: searchResults.data.personalDetailsList,
             };
-            columns = SearchUIUtils.getColumnsToShow(submitterAccountID, data, [], false);
+            columns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data,
+                visibleColumns: [],
+                isExpenseReportView: false,
+            });
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.FROM);
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.TO);
 
             // Test 7: Multiple columns should show when transactions have different fields
-            columns = SearchUIUtils.getColumnsToShow(submitterAccountID, [merchantTransaction, categoryTransaction, tagTransaction], [], false);
+            columns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data: [merchantTransaction, categoryTransaction, tagTransaction],
+                visibleColumns: [],
+                isExpenseReportView: false,
+            });
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.MERCHANT);
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.CATEGORY);
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.TAG);
@@ -7013,7 +7086,12 @@ describe('SearchUIUtils', () => {
             };
 
             // In expense report view, From/To columns should not be shown
-            const columns = SearchUIUtils.getColumnsToShow(submitterAccountID, [testTransaction], [], true);
+            const columns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data: [testTransaction],
+                visibleColumns: [],
+                isExpenseReportView: true,
+            });
 
             // These columns should be shown based on data
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.MERCHANT);
@@ -7050,7 +7128,15 @@ describe('SearchUIUtils', () => {
                 billable: false,
             };
 
-            const columns = SearchUIUtils.getColumnsToShow(submitterAccountID, [reimbursableTransaction, nonReimbursableTransaction], [], true, undefined, undefined, false, true, true);
+            const columns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data: [reimbursableTransaction, nonReimbursableTransaction],
+                visibleColumns: [],
+                isExpenseReportView: true,
+                isExpenseReportViewFromIOUReport: false,
+                shouldShowBillableColumn: true,
+                shouldShowReimbursableColumn: true,
+            });
 
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.BILLABLE);
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.REIMBURSABLE);
@@ -7085,7 +7171,15 @@ describe('SearchUIUtils', () => {
                 billable: true,
             };
 
-            const columns = SearchUIUtils.getColumnsToShow(submitterAccountID, [reimbursableTransaction1, reimbursableTransaction2], [], true, undefined, undefined, false, true, false);
+            const columns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data: [reimbursableTransaction1, reimbursableTransaction2],
+                visibleColumns: [],
+                isExpenseReportView: true,
+                isExpenseReportViewFromIOUReport: false,
+                shouldShowBillableColumn: true,
+                shouldShowReimbursableColumn: false,
+            });
 
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.BILLABLE);
             expect(columns).not.toContain(CONST.SEARCH.TABLE_COLUMNS.REIMBURSABLE);
@@ -7105,7 +7199,12 @@ describe('SearchUIUtils', () => {
                 managerID: adminAccountID,
             };
 
-            const columns = SearchUIUtils.getColumnsToShow(submitterAccountID, [testTransaction], [], false);
+            const columns = SearchUIUtils.getColumnsToShow({
+                currentAccountID: submitterAccountID,
+                data: [testTransaction],
+                visibleColumns: [],
+                isExpenseReportView: false,
+            });
 
             // Should show merchant column because modifiedMerchant has value
             expect(columns).toContain(CONST.SEARCH.TABLE_COLUMNS.MERCHANT);

From 3a4438d2cce759b64ba100e9acb801b39af5deb1 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Fri, 20 Mar 2026 14:34:51 +0700
Subject: [PATCH 10/21] fix attendee avatar

---
 src/components/TransactionItemRow/index.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index 34fc92eaeb66..b935e87b7e41 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -287,7 +287,7 @@ function TransactionItemRow({
             transactionAttendees.map((attendee) => ({
                 id: attendee.accountID ?? CONST.DEFAULT_NUMBER_ID,
                 name: attendee.displayName ?? attendee.email,
-                source: (attendee.avatarUrl || getDefaultAvatar({accountID: attendee.accountID, defaultAvatars})) ?? '',
+                source: (attendee.avatarUrl || getDefaultAvatar({accountID: attendee.accountID, accountEmail: attendee.email, defaultAvatars})) ?? '',
                 type: CONST.ICON_TYPE_AVATAR,
             })),
         [defaultAvatars, transactionAttendees],

From 4e9cea807c0d3964083f2bf936e4ce4ee0ac4b29 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Mon, 23 Mar 2026 21:02:08 +0700
Subject: [PATCH 11/21] update avatar size

---
 src/components/TransactionItemRow/index.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index b935e87b7e41..97606296dbeb 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -551,7 +551,7 @@ function TransactionItemRow({
                                     textStyle: [styles.textMicroBold, styles.buttonSuccessText],
                                     overlayStyle: StyleUtils.getBackgroundColorWithOpacityStyle(colors.productDark400, variables.overlayOpacity),
                                 }}
-                                size={CONST.AVATAR_SIZE.SUBSCRIPT}
+                                size={CONST.AVATAR_SIZE.SMALLER}
                                 isInReportAction
                             />
                         )}

From c960ff0e74d25332c8a3d7e20da02087fad382e4 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Mon, 23 Mar 2026 21:06:30 +0700
Subject: [PATCH 12/21] update shouldShowAttendees conditon for each
 transaction

---
 src/components/TransactionItemRow/index.tsx | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index 97606296dbeb..b5416c32a4e9 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -51,6 +51,7 @@ import {
     isScanning,
     isTimeRequest,
     isUnreportedAndHasInvalidDistanceRateTransaction,
+    shouldShowAttendees as shouldShowAttendeesUtils,
 } from '@libs/TransactionUtils';
 import {getDefaultAvatar} from '@libs/UserAvatarUtils';
 import colors from '@styles/theme/colors';
@@ -293,6 +294,8 @@ function TransactionItemRow({
         [defaultAvatars, transactionAttendees],
     );
 
+    const shouldShowAttendees = shouldShowAttendeesUtils(CONST.IOU.TYPE.SUBMIT, policy) && attendeeIcons.length > 0;
+
     const totalPerAttendee = useMemo(() => {
         const attendeesCount = transactionAttendees.length ?? 0;
         const totalAmount = getAmount(transactionItem);
@@ -538,7 +541,7 @@ function TransactionItemRow({
                         key={column}
                         style={[StyleUtils.getReportTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.ATTENDEES)]}
                     >
-                        {!!attendeeIcons.length && (
+                        {shouldShowAttendees && (
                             <ReportActionAvatars
                                 customAvatars={attendeeIcons}
                                 customAvatarType={CONST.REPORT_ACTION_AVATARS.TYPE.MULTIPLE_HORIZONTAL}
@@ -597,7 +600,7 @@ function TransactionItemRow({
                         key={column}
                         style={[StyleUtils.getReportTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE, undefined, isAmountColumnWide)]}
                     >
-                        {!!attendeeIcons.length && (
+                        {shouldShowAttendees && (
                             <TextWithTooltip
                                 testID="TotalPerAttendeeCell"
                                 shouldShowTooltip

From 57aa4f0a1e7c99371c48742a18196938a6a46396 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Tue, 24 Mar 2026 14:26:04 +0700
Subject: [PATCH 13/21] implement AttendeesCell component

---
 .../ReportActionAvatar.tsx                    |  19 +--
 src/components/ReportActionAvatars/index.tsx  |  17 +--
 .../Search/AttendeesCell.tsx                  | 139 ++++++++++++++++++
 src/components/TransactionItemRow/index.tsx   |  34 +++--
 src/styles/utils/index.ts                     |   4 +-
 5 files changed, 164 insertions(+), 49 deletions(-)
 create mode 100644 src/components/SelectionListWithSections/Search/AttendeesCell.tsx

diff --git a/src/components/ReportActionAvatars/ReportActionAvatar.tsx b/src/components/ReportActionAvatars/ReportActionAvatar.tsx
index 02143753c6f2..aad0061dfbc0 100644
--- a/src/components/ReportActionAvatars/ReportActionAvatar.tsx
+++ b/src/components/ReportActionAvatars/ReportActionAvatar.tsx
@@ -1,6 +1,6 @@
 import lodashSortBy from 'lodash/sortBy';
 import React, {useMemo} from 'react';
-import type {ColorValue, ImageStyle, StyleProp, TextStyle, ViewStyle} from 'react-native';
+import type {ColorValue, ImageStyle, StyleProp, ViewStyle} from 'react-native';
 import {View} from 'react-native';
 import type {ValueOf} from 'type-fest';
 import type {UpperCaseCharacters} from 'type-fest/source/internal';
@@ -55,15 +55,6 @@ type HorizontalStacking = Partial<{
 
     /** Prop to sort the avatars */
     sort: SortingOptions | SortingOptions[];
-
-    /** Border color for the active avatar */
-    pressedBorderColor?: string;
-
-    /** Inner text style */
-    textStyle?: StyleProp<TextStyle>;
-
-    /** Style for the overlay */
-    overlayStyle?: StyleProp<ViewStyle>;
 }>;
 
 type AvatarStyles = {
@@ -317,9 +308,6 @@ function ReportActionAvatarMultipleHorizontal({
     useProfileNavigationWrapper,
     fallbackDisplayName,
     reportID,
-    pressedBorderColor,
-    textStyle,
-    overlayStyle,
 }: HorizontalStacking & {
     size: ValueOf<typeof CONST.AVATAR_SIZE>;
     shouldShowTooltip: boolean;
@@ -405,7 +393,6 @@ function ReportActionAvatarMultipleHorizontal({
                                     isInReportAction,
                                     shouldUseCardBackground,
                                     isActive,
-                                    customPressedBorderColor: pressedBorderColor,
                                 }),
                                 StyleUtils.getAvatarBorderWidth(size),
                             ]}
@@ -438,19 +425,17 @@ function ReportActionAvatarMultipleHorizontal({
                                 isPressed,
                                 isInReportAction,
                                 shouldUseCardBackground,
-                                customPressedBorderColor: pressedBorderColor,
                             }),
 
                             // Set overlay background color with RGBA value so that the text will not inherit opacity
                             StyleUtils.getBackgroundColorWithOpacityStyle(theme.overlay, variables.overlayOpacity),
                             StyleUtils.getHorizontalStackedOverlayAvatarStyle(oneAvatarSize, oneAvatarBorderWidth),
                             icons.at(3)?.type === CONST.ICON_TYPE_WORKSPACE && StyleUtils.getAvatarBorderRadius(size, icons.at(3)?.type),
-                            overlayStyle,
                         ]}
                     >
                         <View style={[styles.justifyContentCenter, styles.alignItemsCenter, StyleUtils.getHeight(oneAvatarSize.height), StyleUtils.getWidthStyle(oneAvatarSize.width)]}>
                             <Text
-                                style={[styles.avatarInnerTextSmall, StyleUtils.getAvatarExtraFontSizeStyle(size), styles.userSelectNone, textStyle]}
+                                style={[styles.avatarInnerTextSmall, StyleUtils.getAvatarExtraFontSizeStyle(size), styles.userSelectNone]}
                                 dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
                             >{`+${avatars.length - maxAvatarsInRow}`}</Text>
                         </View>
diff --git a/src/components/ReportActionAvatars/index.tsx b/src/components/ReportActionAvatars/index.tsx
index 51375346949f..5f49c30b4c40 100644
--- a/src/components/ReportActionAvatars/index.tsx
+++ b/src/components/ReportActionAvatars/index.tsx
@@ -7,7 +7,6 @@ import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import type {InvitedEmailsToAccountIDs, Policy, Report, ReportAction} from '@src/types/onyx';
 import type {CardFeed} from '@src/types/onyx/CardFeeds';
-import type {Icon as IconType} from '@src/types/onyx/OnyxCommon';
 import type {HorizontalStacking} from './ReportActionAvatar';
 import ReportActionAvatar from './ReportActionAvatar';
 import useReportActionAvatars from './useReportActionAvatars';
@@ -74,12 +73,6 @@ type ReportActionAvatarsProps = {
 
     /** chatReportID needed for the avatars logic. When provided, this will be used as a fallback if the snapshot is undefined */
     chatReportID?: string;
-
-    /** Custom avatars to display instead of the avatars from the hook */
-    customAvatars?: IconType[];
-
-    /** Custom avatar type to display instead of the avatar type from the hook */
-    customAvatarType?: ValueOf<typeof CONST.REPORT_ACTION_AVATARS.TYPE>;
 };
 
 /**
@@ -113,8 +106,6 @@ function ReportActionAvatars({
     invitedEmailsToAccountIDs,
     shouldUseCustomFallbackAvatar = false,
     chatReportID,
-    customAvatars,
-    customAvatarType,
 }: ReportActionAvatarsProps) {
     const accountIDs = passedAccountIDs.filter((accountID) => accountID !== CONST.DEFAULT_NUMBER_ID);
 
@@ -135,7 +126,7 @@ function ReportActionAvatars({
 
     const {
         avatarType: notPreciseAvatarType,
-        avatars,
+        avatars: icons,
         details: {delegateAccountID},
         source,
     } = useReportActionAvatars({
@@ -152,8 +143,6 @@ function ReportActionAvatars({
         chatReportID,
     });
 
-    const icons = customAvatars ?? avatars;
-
     let avatarType: ValueOf<typeof CONST.REPORT_ACTION_AVATARS.TYPE> = notPreciseAvatarType;
 
     if (avatarType === CONST.REPORT_ACTION_AVATARS.TYPE.MULTIPLE && !icons.length) {
@@ -164,10 +153,6 @@ function ReportActionAvatars({
         avatarType = shouldStackHorizontally ? CONST.REPORT_ACTION_AVATARS.TYPE.MULTIPLE_HORIZONTAL : CONST.REPORT_ACTION_AVATARS.TYPE.MULTIPLE_DIAGONAL;
     }
 
-    if (customAvatarType) {
-        avatarType = customAvatarType;
-    }
-
     const [primaryAvatar, secondaryAvatar] = icons;
 
     if (avatarType === CONST.REPORT_ACTION_AVATARS.TYPE.SUBSCRIPT && (!!secondaryAvatar?.name || !!subscriptCardFeed)) {
diff --git a/src/components/SelectionListWithSections/Search/AttendeesCell.tsx b/src/components/SelectionListWithSections/Search/AttendeesCell.tsx
new file mode 100644
index 000000000000..ab898a9123eb
--- /dev/null
+++ b/src/components/SelectionListWithSections/Search/AttendeesCell.tsx
@@ -0,0 +1,139 @@
+import React, {useMemo} from 'react';
+import {View} from 'react-native';
+import Avatar from '@components/Avatar';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
+import UserDetailsTooltip from '@components/UserDetailsTooltip';
+import useDefaultAvatars from '@hooks/useDefaultAvatars';
+import useLocalize from '@hooks/useLocalize';
+import useOnyx from '@hooks/useOnyx';
+import useStyleUtils from '@hooks/useStyleUtils';
+import useTheme from '@hooks/useTheme';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {getUserDetailTooltipText, sortIconsByName} from '@libs/ReportUtils';
+import {getDefaultAvatar} from '@libs/UserAvatarUtils';
+import colors from '@styles/theme/colors';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import type {Attendee} from '@src/types/onyx/IOU';
+import type {Icon as IconType} from '@src/types/onyx/OnyxCommon';
+
+type AttendeesCellProps = {
+    attendees: Attendee[];
+    isHovered: boolean;
+    isPressed: boolean;
+};
+
+function AttendeesCell({attendees, isHovered, isPressed}: AttendeesCellProps) {
+    const defaultAvatars = useDefaultAvatars();
+    const attendeeIcons: IconType[] = useMemo(
+        () =>
+            attendees.map((attendee) => ({
+                id: attendee.accountID ?? CONST.DEFAULT_NUMBER_ID,
+                name: attendee.displayName ?? attendee.email,
+                source: (attendee.avatarUrl || getDefaultAvatar({accountID: attendee.accountID, accountEmail: attendee.email, defaultAvatars})) ?? '',
+                type: CONST.ICON_TYPE_AVATAR,
+            })),
+        [defaultAvatars, attendees],
+    );
+
+    const theme = useTheme();
+    const styles = useThemeStyles();
+    const StyleUtils = useStyleUtils();
+    const {localeCompare, formatPhoneNumber} = useLocalize();
+
+    const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
+
+    const size = CONST.AVATAR_SIZE.SMALLER;
+    const maxAvatarsInRow = CONST.AVATAR_ROW_SIZE.DEFAULT;
+    const oneAvatarSize = StyleUtils.getAvatarStyle(size);
+    const oneAvatarBorderWidth = StyleUtils.getAvatarBorderWidth(size).borderWidth ?? 0;
+    const overlapSize = oneAvatarSize.width / 3 + 2 * oneAvatarBorderWidth;
+    const height = oneAvatarSize.height;
+    const avatarContainerStyles = StyleUtils.combineStyles([styles.alignItemsCenter, styles.flexRow, StyleUtils.getHeight(height), styles.overflowHidden]);
+
+    const icons = sortIconsByName(attendeeIcons, personalDetails, localeCompare);
+    const tooltipTexts = useMemo(() => icons.map((icon) => getUserDetailTooltipText(Number(icon.id), formatPhoneNumber, icon.name)), [icons, formatPhoneNumber]);
+
+    return (
+        <View
+            style={avatarContainerStyles}
+            testID="AttendeesCell-Row"
+        >
+            {[...icons].splice(0, maxAvatarsInRow).map((icon, index) => (
+                <UserDetailsTooltip
+                    key={`stackedAvatars-${icon.id}`}
+                    accountID={Number(icon.id)}
+                    icon={icon}
+                    fallbackUserDetails={{
+                        // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
+                        displayName: icon.name,
+                    }}
+                    shouldRender
+                >
+                    <View style={[StyleUtils.getHorizontalStackedAvatarStyle(index, overlapSize, -oneAvatarBorderWidth), StyleUtils.getAvatarBorderRadius(size, icon.type)]}>
+                        <Avatar
+                            iconAdditionalStyles={[
+                                StyleUtils.getHorizontalStackedAvatarBorderStyle({
+                                    theme,
+                                    isHovered,
+                                    isPressed,
+                                    isInReportAction: true,
+                                    shouldUseCardBackground: true,
+                                    isActive: false,
+                                    customPressedBorderColor: theme.activeComponentBG,
+                                }),
+                                StyleUtils.getAvatarBorderWidth(size),
+                            ]}
+                            source={icon.source}
+                            size={size}
+                            name={icon.name}
+                            avatarID={icon.id}
+                            type={icon.type}
+                            fallbackIcon={icon.fallbackIcon}
+                            testID="AttendeesCell-Avatar"
+                        />
+                    </View>
+                </UserDetailsTooltip>
+            ))}
+            {icons.length > maxAvatarsInRow && (
+                <Tooltip
+                    // We only want to cap tooltips to only 10 users or so since some reports have hundreds of users, causing performance to degrade.
+                    text={tooltipTexts.slice(maxAvatarsInRow - 1, maxAvatarsInRow + 9).join(', ')}
+                    shouldRender
+                >
+                    <View
+                        testID="AttendeesCell-LimitReached"
+                        style={[
+                            styles.alignItemsCenter,
+                            styles.justifyContentCenter,
+                            StyleUtils.getHorizontalStackedAvatarBorderStyle({
+                                theme,
+                                isHovered,
+                                isPressed,
+                                isInReportAction: true,
+                                shouldUseCardBackground: true,
+                                customPressedBorderColor: theme.activeComponentBG,
+                            }),
+
+                            // Set overlay background color with RGBA value so that the text will not inherit opacity
+                            StyleUtils.getHorizontalStackedOverlayAvatarStyle(oneAvatarSize, oneAvatarBorderWidth),
+                            icons.at(3)?.type === CONST.ICON_TYPE_WORKSPACE && StyleUtils.getAvatarBorderRadius(size, icons.at(3)?.type),
+                            StyleUtils.getBackgroundColorWithOpacityStyle(colors.productDark400, variables.overlayOpacity),
+                        ]}
+                    >
+                        <View style={[styles.justifyContentCenter, styles.alignItemsCenter, StyleUtils.getHeight(oneAvatarSize.height), StyleUtils.getWidthStyle(oneAvatarSize.width)]}>
+                            <Text
+                                style={[styles.avatarInnerTextSmall, StyleUtils.getAvatarExtraFontSizeStyle(size), styles.userSelectNone, styles.textMicroBold, styles.buttonSuccessText]}
+                                dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
+                            >{`+${icons.length - maxAvatarsInRow}`}</Text>
+                        </View>
+                    </View>
+                </Tooltip>
+            )}
+        </View>
+    );
+}
+
+export default AttendeesCell;
diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index b5416c32a4e9..a5e2a3325d6c 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -9,6 +9,7 @@ import RadioButton from '@components/RadioButton';
 import ReportActionAvatars from '@components/ReportActionAvatars';
 import type {SearchColumnType, TableColumnSize} from '@components/Search/types';
 import ActionCell from '@components/SelectionListWithSections/Search/ActionCell';
+import AttendeesCell from '@components/SelectionListWithSections/Search/AttendeesCell';
 import DateCell from '@components/SelectionListWithSections/Search/DateCell';
 import ExportedIconCell from '@components/SelectionListWithSections/Search/ExportedIconCell';
 import StatusCell from '@components/SelectionListWithSections/Search/StatusCell';
@@ -542,20 +543,25 @@ function TransactionItemRow({
                         style={[StyleUtils.getReportTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.ATTENDEES)]}
                     >
                         {shouldShowAttendees && (
-                            <ReportActionAvatars
-                                customAvatars={attendeeIcons}
-                                customAvatarType={CONST.REPORT_ACTION_AVATARS.TYPE.MULTIPLE_HORIZONTAL}
-                                horizontalStacking={{
-                                    sort: CONST.REPORT_ACTION_AVATARS.SORT_BY.NAME,
-                                    useCardBG: true,
-                                    isHovered: isHover,
-                                    isPressed: isSelected,
-                                    pressedBorderColor: theme.activeComponentBG,
-                                    textStyle: [styles.textMicroBold, styles.buttonSuccessText],
-                                    overlayStyle: StyleUtils.getBackgroundColorWithOpacityStyle(colors.productDark400, variables.overlayOpacity),
-                                }}
-                                size={CONST.AVATAR_SIZE.SMALLER}
-                                isInReportAction
+                            // <ReportActionAvatars
+                            //     customAvatars={attendeeIcons}
+                            //     customAvatarType={CONST.REPORT_ACTION_AVATARS.TYPE.MULTIPLE_HORIZONTAL}
+                            //     horizontalStacking={{
+                            //         sort: CONST.REPORT_ACTION_AVATARS.SORT_BY.NAME,
+                            //         useCardBG: true,
+                            //         isHovered: isHover,
+                            //         isPressed: isSelected,
+                            //         pressedBorderColor: theme.activeComponentBG,
+                            //         textStyle: [styles.textMicroBold, styles.buttonSuccessText],
+                            //         overlayStyle: StyleUtils.getBackgroundColorWithOpacityStyle(colors.productDark400, variables.overlayOpacity),
+                            //     }}
+                            //     size={CONST.AVATAR_SIZE.SMALLER}
+                            //     isInReportAction
+                            // />
+                            <AttendeesCell
+                                attendees={transactionAttendees}
+                                isHovered={isHover}
+                                isPressed={isSelected}
                             />
                         )}
                     </View>
diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts
index a6e18dfa34f9..47e7db267db5 100644
--- a/src/styles/utils/index.ts
+++ b/src/styles/utils/index.ts
@@ -868,9 +868,9 @@ function getHorizontalStackedAvatarBorderStyle({
 /**
  * Get computed avatar styles based on position and border size
  */
-function getHorizontalStackedAvatarStyle(index: number, overlapSize: number): ViewStyle {
+function getHorizontalStackedAvatarStyle(index: number, overlapSize: number, firstAvatarMarginLeft = 0): ViewStyle {
     return {
-        marginLeft: index > 0 ? -overlapSize : 0,
+        marginLeft: index > 0 ? -overlapSize : firstAvatarMarginLeft,
         zIndex: index + 2,
     };
 }

From 83c9223320cf3b90669c895542b4bc485b15c45e Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Tue, 24 Mar 2026 14:29:01 +0700
Subject: [PATCH 14/21] fix lint

---
 src/components/TransactionItemRow/index.tsx | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index f4b658313aea..5b176c617923 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -54,8 +54,6 @@ import {
     shouldShowAttendees as shouldShowAttendeesUtils,
 } from '@libs/TransactionUtils';
 import {getDefaultAvatar} from '@libs/UserAvatarUtils';
-import colors from '@styles/theme/colors';
-import variables from '@styles/variables';
 import CONST from '@src/CONST';
 import type {TranslationPaths} from '@src/languages/types';
 import type {PersonalDetails, Policy, Report, ReportAction, TransactionViolation} from '@src/types/onyx';

From 3df12e03f692119e15ca8712bb9447ad93eba009 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Tue, 24 Mar 2026 20:54:33 +0700
Subject: [PATCH 15/21] fix key for attendee cell

---
 src/components/Search/SearchList/ListItem/AttendeesCell.tsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/components/Search/SearchList/ListItem/AttendeesCell.tsx b/src/components/Search/SearchList/ListItem/AttendeesCell.tsx
index ab898a9123eb..55f197ac7b56 100644
--- a/src/components/Search/SearchList/ListItem/AttendeesCell.tsx
+++ b/src/components/Search/SearchList/ListItem/AttendeesCell.tsx
@@ -63,7 +63,8 @@ function AttendeesCell({attendees, isHovered, isPressed}: AttendeesCellProps) {
         >
             {[...icons].splice(0, maxAvatarsInRow).map((icon, index) => (
                 <UserDetailsTooltip
-                    key={`stackedAvatars-${icon.id}`}
+                    // eslint-disable-next-line react/no-array-index-key
+                    key={`stackedAvatars-${icon.id}-${index}`}
                     accountID={Number(icon.id)}
                     icon={icon}
                     fallbackUserDetails={{

From af7ca0499a278a8aa318a198b0b77c9c9bfbeec3 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Tue, 24 Mar 2026 21:21:29 +0700
Subject: [PATCH 16/21] update translation

---
 src/components/TransactionItemRow/index.tsx | 17 +----------------
 src/languages/de.ts                         |  2 +-
 src/languages/en.ts                         |  2 +-
 src/languages/es.ts                         |  2 +-
 src/languages/fr.ts                         |  2 +-
 src/languages/it.ts                         |  2 +-
 src/languages/ja.ts                         |  2 +-
 src/languages/nl.ts                         |  2 +-
 src/languages/pl.ts                         |  2 +-
 src/languages/pt-BR.ts                      |  2 +-
 src/languages/zh-hans.ts                    |  2 +-
 11 files changed, 11 insertions(+), 26 deletions(-)

diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index 5b176c617923..9fa120915253 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -19,7 +19,6 @@ import type {SearchColumnType, TableColumnSize} from '@components/Search/types';
 import Text from '@components/Text';
 import TextWithTooltip from '@components/TextWithTooltip';
 import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
-import useDefaultAvatars from '@hooks/useDefaultAvatars';
 import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
 import useLocalize from '@hooks/useLocalize';
 import useResponsiveLayout from '@hooks/useResponsiveLayout';
@@ -53,11 +52,9 @@ import {
     isUnreportedAndHasInvalidDistanceRateTransaction,
     shouldShowAttendees as shouldShowAttendeesUtils,
 } from '@libs/TransactionUtils';
-import {getDefaultAvatar} from '@libs/UserAvatarUtils';
 import CONST from '@src/CONST';
 import type {TranslationPaths} from '@src/languages/types';
 import type {PersonalDetails, Policy, Report, ReportAction, TransactionViolation} from '@src/types/onyx';
-import type {Icon as IconType} from '@src/types/onyx/OnyxCommon';
 import type {SearchTransactionAction} from '@src/types/onyx/SearchResults';
 import CategoryCell from './DataCells/CategoryCell';
 import ChatBubbleCell from './DataCells/ChatBubbleCell';
@@ -213,7 +210,6 @@ function TransactionItemRow({
     const createdAt = getTransactionCreated(transactionItem);
     const expensicons = useMemoizedLazyExpensifyIcons(['ArrowRight']);
     const currentUserPersonalDetails = useCurrentUserPersonalDetails();
-    const defaultAvatars = useDefaultAvatars();
     const transactionThreadReportID = reportActions ? getIOUActionForTransactionID(reportActions, transactionItem.transactionID)?.childReportID : undefined;
 
     const isDateColumnWide = dateColumnSize === CONST.SEARCH.TABLE_COLUMN_SIZES.WIDE;
@@ -281,18 +277,7 @@ function TransactionItemRow({
 
     const transactionAttendees = useMemo(() => getAttendees(transactionItem, currentUserPersonalDetails), [transactionItem, currentUserPersonalDetails]);
 
-    const attendeeIcons: IconType[] = useMemo(
-        () =>
-            transactionAttendees.map((attendee) => ({
-                id: attendee.accountID ?? CONST.DEFAULT_NUMBER_ID,
-                name: attendee.displayName ?? attendee.email,
-                source: (attendee.avatarUrl || getDefaultAvatar({accountID: attendee.accountID, accountEmail: attendee.email, defaultAvatars})) ?? '',
-                type: CONST.ICON_TYPE_AVATAR,
-            })),
-        [defaultAvatars, transactionAttendees],
-    );
-
-    const shouldShowAttendees = shouldShowAttendeesUtils(CONST.IOU.TYPE.SUBMIT, policy) && attendeeIcons.length > 0;
+    const shouldShowAttendees = shouldShowAttendeesUtils(CONST.IOU.TYPE.SUBMIT, policy) && transactionAttendees.length > 0;
 
     const totalPerAttendee = useMemo(() => {
         const attendeesCount = transactionAttendees.length ?? 0;
diff --git a/src/languages/de.ts b/src/languages/de.ts
index a2b86911a6b3..029af8283be3 100644
--- a/src/languages/de.ts
+++ b/src/languages/de.ts
@@ -1513,7 +1513,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Diese Buchung ist archiviert',
         bookingArchivedDescription: 'Diese Buchung ist archiviert, weil das Reisedatum verstrichen ist. Füge bei Bedarf eine Ausgabe für den endgültigen Betrag hinzu.',
         attendees: 'Teilnehmende',
-        totalPerAttendee: 'Betrag pro Teilnehmendem',
+        totalPerAttendee: 'Pro Teilnehmendem',
         whoIsYourAccountant: 'Wer ist Ihre Steuerberaterin bzw. Ihr Steuerberater?',
         paymentComplete: 'Zahlung abgeschlossen',
         time: 'Zeit',
diff --git a/src/languages/en.ts b/src/languages/en.ts
index 7a9910ac1a06..83d27bb0026c 100644
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -1562,7 +1562,7 @@ const translations = {
         bookingArchived: 'This booking is archived',
         bookingArchivedDescription: 'This booking is archived because the trip date has passed. Add an expense for the final amount if needed.',
         attendees: 'Attendees',
-        totalPerAttendee: 'Amount per attendee',
+        totalPerAttendee: 'Per attendee',
         whoIsYourAccountant: 'Who is your accountant?',
         paymentComplete: 'Payment complete',
         time: 'Time',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 7d6b13c287b9..65d0277e0a8c 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1434,7 +1434,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Esta reserva está archivada',
         bookingArchivedDescription: 'Esta reserva está archivada porque la fecha del viaje ha pasado. Agregue un gasto por el monto final si es necesario.',
         attendees: 'Asistentes',
-        totalPerAttendee: 'Monto por asistente',
+        totalPerAttendee: 'Por asistente',
         whoIsYourAccountant: '¿Quién es tu contador?',
         paymentComplete: 'Pago completo',
         time: 'Tiempo',
diff --git a/src/languages/fr.ts b/src/languages/fr.ts
index 9fb9344e1ff9..8808ca5a6a1d 100644
--- a/src/languages/fr.ts
+++ b/src/languages/fr.ts
@@ -1517,7 +1517,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Cette réservation est archivée',
         bookingArchivedDescription: 'Cette réservation est archivée car la date du voyage est passée. Ajoutez une dépense pour le montant final si nécessaire.',
         attendees: 'Participants',
-        totalPerAttendee: 'Montant par participant',
+        totalPerAttendee: 'Par participant',
         whoIsYourAccountant: 'Qui est votre comptable ?',
         paymentComplete: 'Paiement terminé',
         time: 'Heure',
diff --git a/src/languages/it.ts b/src/languages/it.ts
index 715db1e1409f..aedb0c6b5239 100644
--- a/src/languages/it.ts
+++ b/src/languages/it.ts
@@ -1512,7 +1512,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Questa prenotazione è archiviata',
         bookingArchivedDescription: 'Questa prenotazione è archiviata perché la data del viaggio è passata. Aggiungi una spesa per l’importo finale, se necessario.',
         attendees: 'Partecipanti',
-        totalPerAttendee: 'Importo per partecipante',
+        totalPerAttendee: 'Per partecipante',
         whoIsYourAccountant: 'Chi è il tuo commercialista?',
         paymentComplete: 'Pagamento completato',
         time: 'Ora',
diff --git a/src/languages/ja.ts b/src/languages/ja.ts
index 0cd6d21625aa..f7c26061a0b4 100644
--- a/src/languages/ja.ts
+++ b/src/languages/ja.ts
@@ -1493,7 +1493,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'この予約はアーカイブされています',
         bookingArchivedDescription: 'この予約は旅行日が過ぎたためアーカイブされています。必要に応じて、最終金額の経費を追加してください。',
         attendees: '参加者',
-        totalPerAttendee: '参加者一人あたりの金額',
+        totalPerAttendee: '参加者ごと',
         whoIsYourAccountant: 'あなたの会計士は誰ですか？',
         paymentComplete: '支払いが完了しました',
         time: '時間',
diff --git a/src/languages/nl.ts b/src/languages/nl.ts
index 95f28a4156cd..1c7583745416 100644
--- a/src/languages/nl.ts
+++ b/src/languages/nl.ts
@@ -1509,7 +1509,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Deze boeking is gearchiveerd',
         bookingArchivedDescription: 'Deze boeking is gearchiveerd omdat de reisdatum is verstreken. Voeg indien nodig een uitgave toe voor het eindbedrag.',
         attendees: 'Deelnemers',
-        totalPerAttendee: 'Bedrag per deelnemer',
+        totalPerAttendee: 'Per deelnemer',
         whoIsYourAccountant: 'Wie is jouw accountant?',
         paymentComplete: 'Betaling voltooid',
         time: 'Tijd',
diff --git a/src/languages/pl.ts b/src/languages/pl.ts
index b11d4014c83a..5e3de5a88e28 100644
--- a/src/languages/pl.ts
+++ b/src/languages/pl.ts
@@ -1508,7 +1508,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Ta rezerwacja jest zarchiwizowana',
         bookingArchivedDescription: 'Ta rezerwacja została zarchiwizowana, ponieważ data podróży już minęła. W razie potrzeby dodaj wydatek na ostateczną kwotę.',
         attendees: 'Uczestnicy',
-        totalPerAttendee: 'Kwota na uczestnika',
+        totalPerAttendee: 'Na uczestnika',
         whoIsYourAccountant: 'Kim jest twój księgowy?',
         paymentComplete: 'Płatność zakończona',
         time: 'Czas',
diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts
index 28db44d9087d..cea1c4e89cbe 100644
--- a/src/languages/pt-BR.ts
+++ b/src/languages/pt-BR.ts
@@ -1506,7 +1506,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: 'Esta reserva está arquivada',
         bookingArchivedDescription: 'Esta reserva está arquivada porque a data da viagem já passou. Adicione uma despesa com o valor final, se necessário.',
         attendees: 'Participantes',
-        totalPerAttendee: 'Valor por participante',
+        totalPerAttendee: 'Por participante',
         whoIsYourAccountant: 'Quem é seu contador?',
         paymentComplete: 'Pagamento concluído',
         time: 'Hora',
diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts
index 4e82097c7385..3f16e11ecff1 100644
--- a/src/languages/zh-hans.ts
+++ b/src/languages/zh-hans.ts
@@ -1465,7 +1465,7 @@ const translations: TranslationDeepObject<typeof en> = {
         bookingArchived: '此预订已归档',
         bookingArchivedDescription: '此预订已归档，因为行程日期已过。如有需要，请为最终金额添加一笔报销。',
         attendees: '参与者',
-        totalPerAttendee: '每位参与者金额',
+        totalPerAttendee: '每位参与者',
         whoIsYourAccountant: '你的会计是谁？',
         paymentComplete: '付款完成',
         time: '时间',

From 8966c13356674aa28293a0189da4a5c06b15b034 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Thu, 26 Mar 2026 22:36:58 +0700
Subject: [PATCH 17/21] fix crash bug

---
 src/libs/SearchUIUtils.ts | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/libs/SearchUIUtils.ts b/src/libs/SearchUIUtils.ts
index fe80eabc214e..6a71eb201a87 100644
--- a/src/libs/SearchUIUtils.ts
+++ b/src/libs/SearchUIUtils.ts
@@ -440,6 +440,8 @@ type TransactionKey = `${typeof ONYXKEYS.COLLECTION.TRANSACTION}${string}`;
 
 type ReportActionKey = `${typeof ONYXKEYS.COLLECTION.REPORT_ACTIONS}${string}`;
 
+type PolicyKey = `${typeof ONYXKEYS.COLLECTION.POLICY}${string}`;
+
 type ViolationKey = `${typeof ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${string}`;
 
 type SearchGroupKey = `${typeof CONST.SEARCH.GROUP_PREFIX}${string}`;
@@ -1191,6 +1193,13 @@ function isTransactionEntry(key: string): key is TransactionKey {
     return key.startsWith(ONYXKEYS.COLLECTION.TRANSACTION);
 }
 
+/**
+ * @private
+ */
+function isPolicyEntry(key: string): key is PolicyKey {
+    return key.startsWith(ONYXKEYS.COLLECTION.POLICY);
+}
+
 /**
  * Determines whether to display the merchant field based on the transactions in the search results.
  */

From e3a8f7e60b6c8e44515f1a3207a977d53a72ab04 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Fri, 27 Mar 2026 14:52:01 +0700
Subject: [PATCH 18/21] fix ts

---
 src/components/Search/FilterDropdowns/SortByPopup.tsx | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/components/Search/FilterDropdowns/SortByPopup.tsx b/src/components/Search/FilterDropdowns/SortByPopup.tsx
index 3d1b3ecc796e..e12a866ad921 100644
--- a/src/components/Search/FilterDropdowns/SortByPopup.tsx
+++ b/src/components/Search/FilterDropdowns/SortByPopup.tsx
@@ -35,7 +35,15 @@ function SortByPopup({searchResults, queryJSON, groupBy, onSort, closeOverlay}:
     const {clearSelectedTransactions} = useSearchActionsContext();
     const [visibleColumns] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, {selector: columnsSelector});
     const searchDataType = shouldUseLiveData ? CONST.SEARCH.DATA_TYPES.EXPENSE_REPORT : searchResults?.search?.type;
-    const currentColumns = !searchResults?.data ? [] : getColumnsToShow(accountID, searchResults?.data, visibleColumns, false, searchDataType, groupBy?.value);
+    const currentColumns = !searchResults?.data
+        ? []
+        : getColumnsToShow({
+              currentAccountID: accountID,
+              data: searchResults?.data,
+              visibleColumns,
+              type: searchDataType,
+              groupBy: groupBy?.value,
+          });
     const sortableColumns = getSortByOptions(currentColumns, translate);
     const sortBy = {text: translate(getSearchColumnTranslationKey(queryJSON.sortBy)), value: queryJSON.sortBy};
 

From 7ad290633e96073c1fad56e2230c0cd5af454fa6 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Tue, 31 Mar 2026 14:59:45 +0700
Subject: [PATCH 19/21] fix attendee avatar

---
 src/libs/TransactionUtils/index.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libs/TransactionUtils/index.ts b/src/libs/TransactionUtils/index.ts
index 98e6f2b3ad7e..de1c92d24b23 100644
--- a/src/libs/TransactionUtils/index.ts
+++ b/src/libs/TransactionUtils/index.ts
@@ -1178,7 +1178,7 @@ function getReportOwnerAsAttendee(transaction: OnyxInputOrEntry<Transaction>, cu
                 accountID: creatorAccountID,
                 text: creatorDisplayName,
                 searchText: creatorDisplayName,
-                avatarUrl: creatorDetails?.avatarThumbnail ?? '',
+                avatarUrl: (creatorDetails?.avatarThumbnail ?? creatorDetails?.avatar ?? '') as string,
                 selected: true,
             };
         }

From f3ae72458c2b9945c0f6df007ddc57d8ed8219a7 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Wed, 1 Apr 2026 23:11:35 +0700
Subject: [PATCH 20/21] remove useMemo

---
 .../SearchList/ListItem/AttendeesCell.tsx     | 20 ++++++++-----------
 1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/src/components/Search/SearchList/ListItem/AttendeesCell.tsx b/src/components/Search/SearchList/ListItem/AttendeesCell.tsx
index 55f197ac7b56..ea45c07ee33d 100644
--- a/src/components/Search/SearchList/ListItem/AttendeesCell.tsx
+++ b/src/components/Search/SearchList/ListItem/AttendeesCell.tsx
@@ -1,4 +1,4 @@
-import React, {useMemo} from 'react';
+import React from 'react';
 import {View} from 'react-native';
 import Avatar from '@components/Avatar';
 import Text from '@components/Text';
@@ -27,16 +27,12 @@ type AttendeesCellProps = {
 
 function AttendeesCell({attendees, isHovered, isPressed}: AttendeesCellProps) {
     const defaultAvatars = useDefaultAvatars();
-    const attendeeIcons: IconType[] = useMemo(
-        () =>
-            attendees.map((attendee) => ({
-                id: attendee.accountID ?? CONST.DEFAULT_NUMBER_ID,
-                name: attendee.displayName ?? attendee.email,
-                source: (attendee.avatarUrl || getDefaultAvatar({accountID: attendee.accountID, accountEmail: attendee.email, defaultAvatars})) ?? '',
-                type: CONST.ICON_TYPE_AVATAR,
-            })),
-        [defaultAvatars, attendees],
-    );
+    const attendeeIcons: IconType[] = attendees.map((attendee) => ({
+        id: attendee.accountID ?? CONST.DEFAULT_NUMBER_ID,
+        name: attendee.displayName ?? attendee.email,
+        source: (attendee.avatarUrl || getDefaultAvatar({accountID: attendee.accountID, accountEmail: attendee.email, defaultAvatars})) ?? '',
+        type: CONST.ICON_TYPE_AVATAR,
+    }));
 
     const theme = useTheme();
     const styles = useThemeStyles();
@@ -54,7 +50,7 @@ function AttendeesCell({attendees, isHovered, isPressed}: AttendeesCellProps) {
     const avatarContainerStyles = StyleUtils.combineStyles([styles.alignItemsCenter, styles.flexRow, StyleUtils.getHeight(height), styles.overflowHidden]);
 
     const icons = sortIconsByName(attendeeIcons, personalDetails, localeCompare);
-    const tooltipTexts = useMemo(() => icons.map((icon) => getUserDetailTooltipText(Number(icon.id), formatPhoneNumber, icon.name)), [icons, formatPhoneNumber]);
+    const tooltipTexts = icons.map((icon) => getUserDetailTooltipText(Number(icon.id), formatPhoneNumber, icon.name));
 
     return (
         <View

From 3c00f7e7ca9f914532c8fd576e4e4332342db7b2 Mon Sep 17 00:00:00 2001
From: nkdengineer <nkdengineer@outlook.com>
Date: Wed, 1 Apr 2026 23:17:47 +0700
Subject: [PATCH 21/21] show scanning per attendee

---
 src/components/TransactionItemRow/index.tsx | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/src/components/TransactionItemRow/index.tsx b/src/components/TransactionItemRow/index.tsx
index 9977cb3df012..8bff270e24ce 100644
--- a/src/components/TransactionItemRow/index.tsx
+++ b/src/components/TransactionItemRow/index.tsx
@@ -17,7 +17,6 @@ import UserInfoCell from '@components/Search/SearchList/ListItem/UserInfoCell';
 import WorkspaceCell from '@components/Search/SearchList/ListItem/WorkspaceCell';
 import type {SearchColumnType, TableColumnSize} from '@components/Search/types';
 import Text from '@components/Text';
-import TextWithTooltip from '@components/TextWithTooltip';
 import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
 import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
 import useLocalize from '@hooks/useLocalize';
@@ -26,7 +25,6 @@ import useStyleUtils from '@hooks/useStyleUtils';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
 import {isCategoryMissing} from '@libs/CategoryUtils';
-import {convertToDisplayString} from '@libs/CurrencyUtils';
 import getBase62ReportID from '@libs/getBase62ReportID';
 import {getIOUActionForTransactionID} from '@libs/ReportActionsUtils';
 import {getReportName} from '@libs/ReportNameUtils';
@@ -577,11 +575,10 @@ function TransactionItemRow({
                         style={[StyleUtils.getReportTableColumnStyles(CONST.SEARCH.TABLE_COLUMNS.TOTAL_PER_ATTENDEE, undefined, isAmountColumnWide)]}
                     >
                         {shouldShowAttendees && (
-                            <TextWithTooltip
-                                testID="TotalPerAttendeeCell"
-                                shouldShowTooltip
-                                text={convertToDisplayString(totalPerAttendee, getCurrency(transactionItem))}
-                                style={[styles.optionDisplayName, styles.pre, styles.justifyContentCenter, styles.textBold, styles.textAlignRight, styles.fontWeightNormal]}
+                            <AmountCell
+                                total={totalPerAttendee ?? 0}
+                                currency={getCurrency(transactionItem)}
+                                isScanning={isScanning(transactionItem)}
                             />
                         )}
                     </View>
