From 93292f7ef05da5c5d2b1ae404b378dca72fbc89a Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 10 Apr 2024 16:43:50 +0200
Subject: [PATCH 01/58] add invoice chat type

---
 src/CONST.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/CONST.ts b/src/CONST.ts
index 74e722cdba59..7f26b9ecaf36 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -52,6 +52,7 @@ const chatTypes = {
     POLICY_ROOM: 'policyRoom',
     POLICY_EXPENSE_CHAT: 'policyExpenseChat',
     SELF_DM: 'selfDM',
+    INVOICE: 'invoiceRoom',
 } as const;
 
 // Explicit type annotation is required

From 1c17dd6eae4add9972ed335118a926ff453e4ade Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 10 Apr 2024 16:44:30 +0200
Subject: [PATCH 02/58] add invoice report type

---
 src/CONST.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/CONST.ts b/src/CONST.ts
index 7f26b9ecaf36..c30f94db6b83 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -791,6 +791,7 @@ const CONST = {
             EXPENSE: 'expense',
             IOU: 'iou',
             TASK: 'task',
+            INVOICE: 'invoice',
         },
         CHAT_TYPE: chatTypes,
         WORKSPACE_CHAT_ROOMS: {

From 08c640b4e670e62bbb478459bda79d1e2af20f8d Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 10 Apr 2024 16:45:40 +0200
Subject: [PATCH 03/58] create isInvoiceRoom and isInvoiceReport

---
 src/libs/ReportUtils.ts | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index f7b160bd67e2..9f1ebb40c0c2 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -5898,6 +5898,20 @@ function canReportBeMentionedWithinPolicy(report: OnyxEntry<Report>, policyID: s
     return isChatRoom(report) && !isThread(report);
 }
 
+/**
+ * Check if Report is an invoice room
+ */
+function isInvoiceRoom(report: OnyxEntry<Report>): boolean {
+    return getChatType(report) === CONST.REPORT.CHAT_TYPE.INVOICE;
+}
+
+/**
+ * Check if Report is an invoice report
+ */
+function isInvoiceReport(report: OnyxEntry<Report> | EmptyObject): boolean {
+    return report?.type === CONST.REPORT.TYPE.INVOICE;
+}
+
 export {
     getReportParticipantsTitle,
     isReportMessageAttachment,
@@ -6134,6 +6148,8 @@ export {
     buildParticipantsFromAccountIDs,
     canReportBeMentionedWithinPolicy,
     getAllHeldTransactions,
+    isInvoiceRoom,
+    isInvoiceReport,
 };
 
 export type {

From 10c2d2fb9f4427b06995771abe6c52397cdcc0ee Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 10 Apr 2024 16:47:31 +0200
Subject: [PATCH 04/58] check isInvoiceReport in report screen

---
 src/pages/home/ReportScreen.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx
index 332e9b080558..7e31b69779c2 100644
--- a/src/pages/home/ReportScreen.tsx
+++ b/src/pages/home/ReportScreen.tsx
@@ -343,7 +343,7 @@ function ReportScreen({
         Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(route.params.reportID));
     }, [transactionThreadReportID, route.params.reportActionID, route.params.reportID]);
 
-    if (ReportUtils.isMoneyRequestReport(report)) {
+    if (ReportUtils.isMoneyRequestReport(report) || ReportUtils.isInvoiceReport(report)) {
         headerView = (
             <MoneyReportHeader
                 report={report}

From 5022a11b055719c155a7cb5a04099376208e94bf Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 10 Apr 2024 16:49:26 +0200
Subject: [PATCH 05/58] check that invoice room is chat room

---
 src/libs/ReportUtils.ts | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 9f1ebb40c0c2..b92c7d4b9b50 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -905,11 +905,25 @@ function isPaidGroupPolicyExpenseReport(report: OnyxEntry<Report>): boolean {
     return isExpenseReport(report) && isPaidGroupPolicy(report);
 }
 
+/**
+ * Check if Report is an invoice room
+ */
+function isInvoiceRoom(report: OnyxEntry<Report>): boolean {
+    return getChatType(report) === CONST.REPORT.CHAT_TYPE.INVOICE;
+}
+
+/**
+ * Check if Report is an invoice report
+ */
+function isInvoiceReport(report: OnyxEntry<Report> | EmptyObject): boolean {
+    return report?.type === CONST.REPORT.TYPE.INVOICE;
+}
+
 /**
  * Whether the provided report is a chat room
  */
 function isChatRoom(report: OnyxEntry<Report>): boolean {
-    return isUserCreatedPolicyRoom(report) || isDefaultRoom(report);
+    return isUserCreatedPolicyRoom(report) || isDefaultRoom(report) || isInvoiceRoom(report);
 }
 
 /**
@@ -5898,20 +5912,6 @@ function canReportBeMentionedWithinPolicy(report: OnyxEntry<Report>, policyID: s
     return isChatRoom(report) && !isThread(report);
 }
 
-/**
- * Check if Report is an invoice room
- */
-function isInvoiceRoom(report: OnyxEntry<Report>): boolean {
-    return getChatType(report) === CONST.REPORT.CHAT_TYPE.INVOICE;
-}
-
-/**
- * Check if Report is an invoice report
- */
-function isInvoiceReport(report: OnyxEntry<Report> | EmptyObject): boolean {
-    return report?.type === CONST.REPORT.TYPE.INVOICE;
-}
-
 export {
     getReportParticipantsTitle,
     isReportMessageAttachment,
@@ -5929,6 +5929,8 @@ export {
     isAdminsOnlyPostingRoom,
     isAnnounceRoom,
     isUserCreatedPolicyRoom,
+    isInvoiceRoom,
+    isInvoiceReport,
     isChatRoom,
     getChatRoomSubtitle,
     getParentNavigationSubtitle,
@@ -6148,8 +6150,6 @@ export {
     buildParticipantsFromAccountIDs,
     canReportBeMentionedWithinPolicy,
     getAllHeldTransactions,
-    isInvoiceRoom,
-    isInvoiceReport,
 };
 
 export type {

From 86f52ca2cea996d56e5acfcaf66fac4413f5af95 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 10 Apr 2024 16:55:17 +0200
Subject: [PATCH 06/58] implement invoice room welcome message

---
 src/languages/en.ts     | 1 +
 src/languages/es.ts     | 1 +
 src/libs/ReportUtils.ts | 2 ++
 3 files changed, 4 insertions(+)

diff --git a/src/languages/en.ts b/src/languages/en.ts
index 9451407c822f..20779fa561a6 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -519,6 +519,7 @@ export default {
             // eslint-disable-next-line @typescript-eslint/naming-convention
             'track-expense': 'track an expense',
         },
+        beginningOfChatHistoryInvoiceRoom: 'Collaboration starts here! 🎉 \nUse this room to view, discuss, and pay invoices.',
     },
     reportAction: {
         asCopilot: 'as copilot for',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index a56c8ac2739d..0d55f4a902dd 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -515,6 +515,7 @@ export default {
             // eslint-disable-next-line @typescript-eslint/naming-convention
             'track-expense': 'rastrear un gasto',
         },
+        beginningOfChatHistoryInvoiceRoom: '¡Este es el lugar para colaborar! 🎉\nUsa esta sala para ver, discutir y pagar facturas.',
     },
     reportAction: {
         asCopilot: 'como copiloto de',
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index b92c7d4b9b50..123610acbf34 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -1497,6 +1497,8 @@ function getRoomWelcomeMessage(report: OnyxEntry<Report>, isUserPolicyAdmin: boo
     } else if (isAnnounceRoom(report)) {
         welcomeMessage.phrase1 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryAnnounceRoomPartOne', {workspaceName});
         welcomeMessage.phrase2 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryAnnounceRoomPartTwo', {workspaceName});
+    } else if (isInvoiceRoom(report)) {
+        welcomeMessage.phrase1 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryInvoiceRoom');
     } else {
         // Message for user created rooms or other room types.
         welcomeMessage.phrase1 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryUserRoomPartOne');

From f9243bbde5a65a264b46620fb83cf8ef86806574 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 10 Apr 2024 17:00:11 +0200
Subject: [PATCH 07/58] accept invoice report in AvatarWithDisplayName

---
 src/components/AvatarWithDisplayName.tsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx
index f6afb4dae2d6..4171a3170534 100644
--- a/src/components/AvatarWithDisplayName.tsx
+++ b/src/components/AvatarWithDisplayName.tsx
@@ -60,7 +60,8 @@ function AvatarWithDisplayName({
     const title = ReportUtils.getReportName(report);
     const subtitle = ReportUtils.getChatRoomSubtitle(report);
     const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(report);
-    const isMoneyRequestOrReport = ReportUtils.isMoneyRequestReport(report) || ReportUtils.isMoneyRequest(report) || ReportUtils.isTrackExpenseReport(report);
+    const isMoneyRequestOrReport =
+        ReportUtils.isMoneyRequestReport(report) || ReportUtils.isMoneyRequest(report) || ReportUtils.isTrackExpenseReport(report) || ReportUtils.isInvoiceReport(report);
     const icons = ReportUtils.getIcons(report, personalDetails, null, '', -1, policy);
     const ownerPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(report?.ownerAccountID ? [report.ownerAccountID] : [], personalDetails);
     const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(Object.values(ownerPersonalDetails) as PersonalDetails[], false);

From c15f33d6442772f84ae03394f018049e06ac6ae8 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 10 Apr 2024 17:05:08 +0200
Subject: [PATCH 08/58] support invoice report in getChatRoomSubtitle

---
 src/libs/ReportUtils.ts | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 123610acbf34..1669a619d14d 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -3062,6 +3062,9 @@ function getChatRoomSubtitle(report: OnyxEntry<Report>): string | undefined {
     if (isArchivedRoom(report)) {
         return report?.oldPolicyName ?? '';
     }
+    if (isInvoiceRoom(report)) {
+        return Localize.translateLocal('workspace.common.invoices');
+    }
     return getPolicyName(report);
 }
 

From e08889ed8dd3c3e7c75a1abb8496d8d40468b020 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 10 Apr 2024 17:07:40 +0200
Subject: [PATCH 09/58] accept invoice room in shouldReportShowSubscript

---
 src/libs/ReportUtils.ts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 1669a619d14d..2f054cc60788 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -5112,6 +5112,10 @@ function shouldReportShowSubscript(report: OnyxEntry<Report>): boolean {
         return true;
     }
 
+    if (isInvoiceRoom(report)) {
+        return true;
+    }
+
     return false;
 }
 

From 2d67b99043a1194c72959c7736fc69874f91e75e Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 10 Apr 2024 17:54:33 +0200
Subject: [PATCH 10/58] integrate invoice room in canLeaveRoom

---
 src/libs/ReportUtils.ts | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 2f054cc60788..0b30e1d9676e 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -5041,8 +5041,15 @@ function getMoneyRequestOptions(report: OnyxEntry<Report>, policy: OnyxEntry<Pol
  * `domain` - Nobody can leave (it's auto-shared with domain members)
  * `dm` - Nobody can leave (it's auto-shared with users)
  * `private` - Anybody can leave (though you can only be invited to join)
+ * `invoice` - Invoice sender, invoice receiver and auto-invited admins cannot leave
  */
 function canLeaveRoom(report: OnyxEntry<Report>, isPolicyMember: boolean): boolean {
+    if (report?.chatType === CONST.REPORT.CHAT_TYPE.INVOICE) {
+        const isAdmin = !!Object.entries(report.participants ?? {}).find(([participantID, {role}]) => Number(participantID) === currentUserAccountID && role !== CONST.POLICY.ROLE.ADMIN);
+
+        return report.managerID !== currentUserAccountID && report.ownerAccountID !== currentUserAccountID && !isAdmin;
+    }
+
     if (!report?.visibility) {
         if (
             report?.chatType === CONST.REPORT.CHAT_TYPE.POLICY_ADMINS ||

From 3e946169042201531aee923417eff56e7bf9b5af Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 10 Apr 2024 18:17:48 +0200
Subject: [PATCH 11/58] integrate invoice icon in getIcons

---
 src/libs/ReportUtils.ts  | 17 +++++++++++++++++
 src/types/onyx/Report.ts |  2 ++
 2 files changed, 19 insertions(+)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 0b30e1d9676e..97c6f59ed26f 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -1955,6 +1955,23 @@ function getIcons(
         return [groupChatIcon];
     }
 
+    if (isInvoiceRoom(report)) {
+        const workspaceIcon = getWorkspaceIcon(report, policy);
+
+        const receiverPolicyID = Object.values(report.participants ?? {})?.find((participant) => participant.type === 'policy')?.policyID ?? '';
+        const receiverPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${receiverPolicyID}`];
+        const isWorkspaceToWorkspace = !!receiverPolicyID && receiverPolicy;
+        const icons = [];
+
+        if (isWorkspaceToWorkspace) {
+            icons.push(getWorkspaceIcon(report, receiverPolicy));
+        } else {
+            icons.push(...getIconsForParticipants(report?.participantAccountIDs ?? [], personalDetails));
+        }
+
+        return [workspaceIcon, ...icons];
+    }
+
     return getIconsForParticipants(report?.participantAccountIDs ?? [], personalDetails);
 }
 
diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts
index fe3eec6dc11e..cf39d1f0d1bd 100644
--- a/src/types/onyx/Report.ts
+++ b/src/types/onyx/Report.ts
@@ -26,6 +26,8 @@ type PendingChatMember = {
 type Participant = {
     hidden?: boolean;
     role?: 'admin' | 'member';
+    type?: 'policy' | 'individual';
+    policyID?: string;
 };
 
 type Participants = Record<number, Participant>;

From 8a41a366cd6b76515b1b2cd6809b9e4fe69ccaad Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Thu, 11 Apr 2024 17:56:20 +0200
Subject: [PATCH 12/58] create getInvoicesChatName

---
 src/libs/ReportUtils.ts  | 23 +++++++++++++++++++++++
 src/types/onyx/Report.ts |  4 ++++
 2 files changed, 27 insertions(+)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 97c6f59ed26f..937d54d77702 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -2974,6 +2974,24 @@ function getReportActionMessage(reportAction: ReportAction | EmptyObject, parent
     return reportAction?.message?.[0]?.text ?? '';
 }
 
+/**
+ * Get the title for an invoice room.
+ */
+function getInvoicesChatName(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>): string {
+    const policyName = getPolicyName(report, false, policy);
+    let receiverName = '';
+
+    if (report?.invoiceReceiverAccountID) {
+        receiverName = PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[report.invoiceReceiverAccountID]);
+    }
+
+    if (report?.invoiceReceiverPolicyID) {
+        receiverName = getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report.invoiceReceiverPolicyID}`]);
+    }
+
+    return `${receiverName} & ${policyName}`;
+}
+
 /**
  * Get the title for a report.
  */
@@ -3045,6 +3063,10 @@ function getReportName(report: OnyxEntry<Report>, policy: OnyxEntry<Policy> = nu
         formattedName = getDisplayNameForParticipant(currentUserAccountID, undefined, undefined, true);
     }
 
+    if (isInvoiceRoom(report)) {
+        formattedName = getInvoicesChatName(report, policy);
+    }
+
     if (formattedName) {
         return formattedName;
     }
@@ -5999,6 +6021,7 @@ export {
     getIcons,
     getRoomWelcomeMessage,
     getDisplayNamesWithTooltips,
+    getInvoicesChatName,
     getReportName,
     getReport,
     getReportNotificationPreference,
diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts
index cf39d1f0d1bd..9aba3f2c2a34 100644
--- a/src/types/onyx/Report.ts
+++ b/src/types/onyx/Report.ts
@@ -188,6 +188,10 @@ type Report = OnyxCommon.OnyxValueWithOfflineFeedback<
         transactionThreadReportID?: string;
 
         fieldList?: Record<string, PolicyReportField>;
+
+        // TODO: Confirm
+        invoiceReceiverAccountID?: number;
+        invoiceReceiverPolicyID?: string;
     },
     PolicyReportField['fieldID']
 >;

From 24460570f31f6f00717315b306b26fbfd0e0412c Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 12 Apr 2024 11:11:25 +0200
Subject: [PATCH 13/58] add awaiting payment translation

---
 src/languages/en.ts    | 2 ++
 src/languages/es.ts    | 2 ++
 src/languages/types.ts | 3 +++
 3 files changed, 7 insertions(+)

diff --git a/src/languages/en.ts b/src/languages/en.ts
index 20779fa561a6..df87737eb504 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -9,6 +9,7 @@ import type {
     AlreadySignedInParams,
     AmountEachParams,
     ApprovedAmountParams,
+    AwaitingPaymentParams,
     BeginningOfChatHistoryAdminRoomPartOneParams,
     BeginningOfChatHistoryAnnounceRoomPartOneParams,
     BeginningOfChatHistoryAnnounceRoomPartTwo,
@@ -736,6 +737,7 @@ export default {
         set: 'set',
         changed: 'changed',
         removed: 'removed',
+        awaitingPayment: ({payerName}: AwaitingPaymentParams) => `Awaiting payment by ${payerName}`,
     },
     notificationPreferencesPage: {
         header: 'Notification preferences',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 0d55f4a902dd..280852813fb5 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -7,6 +7,7 @@ import type {
     AlreadySignedInParams,
     AmountEachParams,
     ApprovedAmountParams,
+    AwaitingPaymentParams,
     BeginningOfChatHistoryAdminRoomPartOneParams,
     BeginningOfChatHistoryAnnounceRoomPartOneParams,
     BeginningOfChatHistoryAnnounceRoomPartTwo,
@@ -734,6 +735,7 @@ export default {
         set: 'estableció',
         changed: 'cambió',
         removed: 'eliminó',
+        awaitingPayment: ({payerName}: AwaitingPaymentParams) => `A la espera de pago por ${payerName}`,
     },
     notificationPreferencesPage: {
         header: 'Preferencias de avisos',
diff --git a/src/languages/types.ts b/src/languages/types.ts
index c365363f84af..59e1bfe40af2 100644
--- a/src/languages/types.ts
+++ b/src/languages/types.ts
@@ -135,6 +135,8 @@ type PayerSettledParams = {amount: number | string};
 
 type WaitingOnBankAccountParams = {submitterDisplayName: string};
 
+type AwaitingPaymentParams = {payerName: string};
+
 type CanceledRequestParams = {amount: string; submitterDisplayName: string};
 
 type AdminCanceledRequestParams = {manager: string; amount: string};
@@ -391,6 +393,7 @@ export type {
     ViolationsTagOutOfPolicyParams,
     ViolationsTaxOutOfPolicyParams,
     WaitingOnBankAccountParams,
+    AwaitingPaymentParams,
     WalletProgramParams,
     UsePlusButtonParams,
     WeSentYouMagicSignInLinkParams,

From 8e667005d581a6bb9cccb7d6f398f754f6b97ade Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 12 Apr 2024 11:15:32 +0200
Subject: [PATCH 14/58] create PaymentWaitingBanner

---
 src/components/PaymentWaitingBanner/index.tsx | 31 +++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 src/components/PaymentWaitingBanner/index.tsx

diff --git a/src/components/PaymentWaitingBanner/index.tsx b/src/components/PaymentWaitingBanner/index.tsx
new file mode 100644
index 000000000000..af13711f08e0
--- /dev/null
+++ b/src/components/PaymentWaitingBanner/index.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import {View} from 'react-native';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import useTheme from '@hooks/useTheme';
+import useThemeStyles from '@hooks/useThemeStyles';
+
+type PaymentWaitingBannerProps = {
+    payerName: string;
+};
+
+function PaymentWaitingBanner({payerName}: PaymentWaitingBannerProps) {
+    const theme = useTheme();
+    const styles = useThemeStyles();
+    const {translate} = useLocalize();
+
+    return (
+        <View style={[styles.flexRow, styles.alignItemsCenter]}>
+            <Icon
+                src={Expensicons.Hourglass}
+                fill={theme.icon}
+            />
+
+            <Text style={[styles.inlineSystemMessage, styles.flexShrink1]}>{translate('iou.awaitingPayment', {payerName})}</Text>
+        </View>
+    );
+}
+
+export default PaymentWaitingBanner;

From fd8a5bd6bfc9076a1be48454c84fb289ed58837f Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 12 Apr 2024 11:17:31 +0200
Subject: [PATCH 15/58] create isInvoiceAwaitingPayment

---
 src/libs/ReportUtils.ts | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 937d54d77702..f92c0ad7b5ef 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -5967,6 +5967,13 @@ function canReportBeMentionedWithinPolicy(report: OnyxEntry<Report>, policyID: s
     return isChatRoom(report) && !isThread(report);
 }
 
+/**
+ * Check if a invoice report is awaiting for payment
+ */
+function isInvoiceAwaitingPayment(report: OnyxEntry<Report>): boolean {
+    return !isSettled(report?.reportID ?? '') && isInvoiceReport(report);
+}
+
 export {
     getReportParticipantsTitle,
     isReportMessageAttachment,
@@ -6206,6 +6213,7 @@ export {
     buildParticipantsFromAccountIDs,
     canReportBeMentionedWithinPolicy,
     getAllHeldTransactions,
+    isInvoiceAwaitingPayment,
 };
 
 export type {

From 19175e973c0084c56fcc305fb91b15b7f95904e6 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 12 Apr 2024 11:19:10 +0200
Subject: [PATCH 16/58] render MoneyRequestView in ReportActionItem for invoice

---
 src/pages/home/report/ReportActionItem.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx
index b2922556b71d..06dc68bf8fae 100644
--- a/src/pages/home/report/ReportActionItem.tsx
+++ b/src/pages/home/report/ReportActionItem.tsx
@@ -752,7 +752,7 @@ function ReportActionItem({
                 </View>
             );
         }
-        if (ReportUtils.isExpenseReport(report) || ReportUtils.isIOUReport(report)) {
+        if (ReportUtils.isExpenseReport(report) || ReportUtils.isIOUReport(report) || ReportUtils.isInvoiceReport(report)) {
             return (
                 <OfflineWithFeedback pendingAction={action.pendingAction}>
                     {transactionThreadReport && !isEmptyObject(transactionThreadReport) ? (

From 21fb170d9bd79da63f39c7e902d9c219d31c30c3 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 12 Apr 2024 11:59:31 +0200
Subject: [PATCH 17/58] add invoiceReceiver to report

---
 src/CONST.ts             |  5 +++++
 src/types/onyx/Report.ts | 12 +++++++++---
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/src/CONST.ts b/src/CONST.ts
index c30f94db6b83..9f4fd2c4128b 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -4339,6 +4339,11 @@ const CONST = {
 
     MAX_TAX_RATE_INTEGER_PLACES: 4,
     MAX_TAX_RATE_DECIMAL_PLACES: 4,
+
+    INVOICE_RECEIVER_TYPE: {
+        INDIVIDUAL: 'individual',
+        POLICY: 'policy',
+    },
 } as const;
 
 type Country = keyof typeof CONST.ALL_COUNTRIES;
diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts
index 9aba3f2c2a34..56980094cd71 100644
--- a/src/types/onyx/Report.ts
+++ b/src/types/onyx/Report.ts
@@ -189,9 +189,15 @@ type Report = OnyxCommon.OnyxValueWithOfflineFeedback<
 
         fieldList?: Record<string, PolicyReportField>;
 
-        // TODO: Confirm
-        invoiceReceiverAccountID?: number;
-        invoiceReceiverPolicyID?: string;
+        invoiceReceiver?:
+            | {
+                  type: typeof CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
+                  accountID: number;
+              }
+            | {
+                  type: typeof CONST.INVOICE_RECEIVER_TYPE.POLICY;
+                  policyID: string;
+              };
     },
     PolicyReportField['fieldID']
 >;

From 32536ffaee59a86a1312869d084b40c075e524bb Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 12 Apr 2024 12:04:07 +0200
Subject: [PATCH 18/58] integrate invoiceReceiver usage

---
 src/libs/ReportUtils.ts | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index f92c0ad7b5ef..5321ae30d075 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -2981,12 +2981,12 @@ function getInvoicesChatName(report: OnyxEntry<Report>, policy: OnyxEntry<Policy
     const policyName = getPolicyName(report, false, policy);
     let receiverName = '';
 
-    if (report?.invoiceReceiverAccountID) {
-        receiverName = PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[report.invoiceReceiverAccountID]);
+    if (report?.invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL) {
+        receiverName = PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[report.invoiceReceiver.accountID]);
     }
 
-    if (report?.invoiceReceiverPolicyID) {
-        receiverName = getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report.invoiceReceiverPolicyID}`]);
+    if (report?.invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.POLICY) {
+        receiverName = getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report.invoiceReceiver.policyID}`]);
     }
 
     return `${receiverName} & ${policyName}`;

From 4bad9a2fa580f3ba1291ab57e6c5ee04556aa013 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 12 Apr 2024 12:06:00 +0200
Subject: [PATCH 19/58] add invoice banner to MoneyReportHeader

---
 src/components/MoneyReportHeader.tsx | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx
index 14227d6a2051..befcaf470901 100644
--- a/src/components/MoneyReportHeader.tsx
+++ b/src/components/MoneyReportHeader.tsx
@@ -22,6 +22,7 @@ import ConfirmModal from './ConfirmModal';
 import HeaderWithBackButton from './HeaderWithBackButton';
 import * as Expensicons from './Icon/Expensicons';
 import MoneyReportHeaderStatusBar from './MoneyReportHeaderStatusBar';
+import PaymentWaitingBanner from './PaymentWaitingBanner';
 import ProcessMoneyReportHoldMenu from './ProcessMoneyReportHoldMenu';
 import SettlementButton from './SettlementButton';
 
@@ -99,6 +100,8 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money
 
     const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton;
 
+    const shouldShowWaitingNote = ReportUtils.isInvoiceAwaitingPayment(moneyRequestReport);
+
     const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0;
     const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport);
     const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE;
@@ -108,7 +111,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money
     const formattedAmount = CurrencyUtils.convertToDisplayString(reimbursableSpend, moneyRequestReport.currency);
     const [nonHeldAmount, fullAmount] = ReportUtils.getNonHeldAndFullAmount(moneyRequestReport, policy);
     const displayedAmount = ReportUtils.hasHeldExpenses(moneyRequestReport.reportID) && canAllowSettlement ? nonHeldAmount : formattedAmount;
-    const isMoreContentShown = shouldShowNextStep || (shouldShowAnyButton && isSmallScreenWidth);
+    const isMoreContentShown = shouldShowNextStep || (shouldShowAnyButton && isSmallScreenWidth) || shouldShowWaitingNote;
 
     const confirmPayment = (type?: PaymentMethodType | undefined) => {
         if (!type) {
@@ -263,6 +266,12 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money
                         <MoneyReportHeaderStatusBar nextStep={nextStep} />
                     </View>
                 )}
+                {shouldShowWaitingNote && (
+                    <PaymentWaitingBanner
+                        // TODO: Integrate a getter for the payer name
+                        payerName=""
+                    />
+                )}
             </View>
             {isHoldMenuVisible && requestType !== undefined && (
                 <ProcessMoneyReportHoldMenu

From 4e81a6c86a7a00ffbaa7692f17cf82d29f0cfb24 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 12 Apr 2024 12:11:07 +0200
Subject: [PATCH 20/58] integrate deleted invoice message

---
 src/components/ReportActionItem/MoneyRequestAction.tsx | 2 ++
 src/languages/en.ts                                    | 1 +
 src/languages/es.ts                                    | 1 +
 src/pages/home/report/ReportActionItem.tsx             | 2 ++
 4 files changed, 6 insertions(+)

diff --git a/src/components/ReportActionItem/MoneyRequestAction.tsx b/src/components/ReportActionItem/MoneyRequestAction.tsx
index 7d9ba2697c7a..9bef637bf292 100644
--- a/src/components/ReportActionItem/MoneyRequestAction.tsx
+++ b/src/components/ReportActionItem/MoneyRequestAction.tsx
@@ -116,6 +116,8 @@ function MoneyRequestAction({
             message = 'parentReportAction.reversedTransaction';
         } else if (isTrackExpenseAction) {
             message = 'parentReportAction.deletedExpense';
+        } else if (action.childType === CONST.REPORT.TYPE.INVOICE) {
+            message = 'parentReportAction.deletedInvoice';
         } else {
             message = 'parentReportAction.deletedRequest';
         }
diff --git a/src/languages/en.ts b/src/languages/en.ts
index df87737eb504..b38601420c2d 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -2535,6 +2535,7 @@ export default {
         reversedTransaction: '[Reversed transaction]',
         deletedTask: '[Deleted task]',
         hiddenMessage: '[Hidden message]',
+        deletedInvoice: '[Deleted invoice]',
     },
     threads: {
         thread: 'Thread',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 280852813fb5..2263170425c3 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -3027,6 +3027,7 @@ export default {
         reversedTransaction: '[Transacción anulada]',
         deletedTask: '[Tarea eliminada]',
         hiddenMessage: '[Mensaje oculto]',
+        deletedInvoice: '[Factura eliminada]',
     },
     threads: {
         thread: 'Hilo',
diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx
index 06dc68bf8fae..afc66d15c1f1 100644
--- a/src/pages/home/report/ReportActionItem.tsx
+++ b/src/pages/home/report/ReportActionItem.tsx
@@ -689,6 +689,8 @@ function ReportActionItem({
                     message = 'parentReportAction.reversedTransaction';
                 } else if (ReportActionsUtils.isTrackExpenseAction(parentReportAction)) {
                     message = 'parentReportAction.deletedExpense';
+                } else if (parentReportAction?.childType === CONST.REPORT.TYPE.INVOICE) {
+                    message = 'parentReportAction.deletedInvoice';
                 } else {
                     message = 'parentReportAction.deletedRequest';
                 }

From 19b54e34b25b9d9ddcb7c27ae4b237cdcac744ff Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 12 Apr 2024 12:12:58 +0200
Subject: [PATCH 21/58] integrate deleted invoice message in
 getTransactionReportName

---
 src/libs/ReportUtils.ts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 5321ae30d075..7aa2d4a7278b 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -190,6 +190,7 @@ type OptimisticIOUReportAction = Pick<
     | 'receipt'
     | 'whisperedToAccountIDs'
     | 'childReportID'
+    | 'childType'
 >;
 
 type ReportRouteParams = {
@@ -2676,6 +2677,10 @@ function getTransactionReportName(reportAction: OnyxEntry<ReportAction | Optimis
         return Localize.translateLocal('iou.receiptMissingDetails');
     }
 
+    if (reportAction?.childType === CONST.REPORT.TYPE.INVOICE) {
+        return Localize.translateLocal('parentReportAction.deletedInvoice');
+    }
+
     const transactionDetails = getTransactionDetails(transaction);
 
     return Localize.translateLocal(ReportActionsUtils.isSentMoneyReportAction(reportAction) ? 'iou.threadSentMoneyReportName' : 'iou.threadRequestReportName', {

From ca98bd9383b22f0a90cbe6c854cb46c81355350f Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 12 Apr 2024 12:16:09 +0200
Subject: [PATCH 22/58] add invoice banner to ReportPreview

---
 src/components/ReportActionItem/ReportPreview.tsx | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx
index 190343e48abd..9ff09ad33ec9 100644
--- a/src/components/ReportActionItem/ReportPreview.tsx
+++ b/src/components/ReportActionItem/ReportPreview.tsx
@@ -8,6 +8,7 @@ import Button from '@components/Button';
 import Icon from '@components/Icon';
 import * as Expensicons from '@components/Icon/Expensicons';
 import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import PaymentWaitingBanner from '@components/PaymentWaitingBanner';
 import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
 import RenderHTML from '@components/RenderHTML';
 import SettlementButton from '@components/SettlementButton';
@@ -215,6 +216,8 @@ function ReportPreview({
     const shouldPromptUserToAddBankAccount = ReportUtils.hasMissingPaymentMethod(userWallet, iouReportID);
     const shouldShowRBR = !iouSettled && hasErrors;
 
+    const shouldShowWaitingNote = ReportUtils.isInvoiceAwaitingPayment(iouReport);
+
     /*
      Show subtitle if at least one of the money requests is not being smart scanned, and either:
      - There is more than one money request – in this case, the "X requests, Y scanning" subtitle is shown;
@@ -352,6 +355,12 @@ function ReportPreview({
                                         isDisabled={shouldDisableSubmitButton}
                                     />
                                 )}
+                                {shouldShowWaitingNote && (
+                                    <PaymentWaitingBanner
+                                        // TODO: Integrate a getter for the payer name
+                                        payerName=""
+                                    />
+                                )}
                             </View>
                         </View>
                     </View>

From 89e2eedf79ca35828eb6216d1a12cced528b1155 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 12 Apr 2024 12:17:42 +0200
Subject: [PATCH 23/58] add todo

---
 src/types/onyx/Report.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts
index 56980094cd71..2bad31bc372c 100644
--- a/src/types/onyx/Report.ts
+++ b/src/types/onyx/Report.ts
@@ -26,6 +26,7 @@ type PendingChatMember = {
 type Participant = {
     hidden?: boolean;
     role?: 'admin' | 'member';
+    // TODO: Confirm
     type?: 'policy' | 'individual';
     policyID?: string;
 };

From d83d22aee6806b16db5513a5b2089cc6f2fb335f Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Mon, 15 Apr 2024 14:41:11 +0200
Subject: [PATCH 24/58] invoice is not a default for ReportWelcomeText

---
 src/components/ReportWelcomeText.tsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx
index 219199c25bc3..24d7747a8fc7 100644
--- a/src/components/ReportWelcomeText.tsx
+++ b/src/components/ReportWelcomeText.tsx
@@ -38,7 +38,8 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP
     const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(report);
     const isChatRoom = ReportUtils.isChatRoom(report);
     const isSelfDM = ReportUtils.isSelfDM(report);
-    const isDefault = !(isChatRoom || isPolicyExpenseChat || isSelfDM);
+    const isInvoiceRoom = ReportUtils.isInvoiceRoom(report);
+    const isDefault = !(isChatRoom || isPolicyExpenseChat || isSelfDM || isInvoiceRoom);
     const participantAccountIDs = report?.participantAccountIDs ?? [];
     const isMultipleParticipant = participantAccountIDs.length > 1;
     const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(OptionsListUtils.getPersonalDetailsForAccountIDs(participantAccountIDs, personalDetails), isMultipleParticipant);

From b9ed19d390825fe254c4f36e64d799e85f017e9d Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Mon, 15 Apr 2024 14:41:21 +0200
Subject: [PATCH 25/58] fix welcome message

---
 src/libs/ReportUtils.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 7aa2d4a7278b..8305e90d20d3 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -1499,6 +1499,7 @@ function getRoomWelcomeMessage(report: OnyxEntry<Report>, isUserPolicyAdmin: boo
         welcomeMessage.phrase1 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryAnnounceRoomPartOne', {workspaceName});
         welcomeMessage.phrase2 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryAnnounceRoomPartTwo', {workspaceName});
     } else if (isInvoiceRoom(report)) {
+        welcomeMessage.showReportName = false;
         welcomeMessage.phrase1 = Localize.translateLocal('reportActionsView.beginningOfChatHistoryInvoiceRoom');
     } else {
         // Message for user created rooms or other room types.

From 697de5e4abb4d115b1fbb7897de2cde886df52f6 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Mon, 15 Apr 2024 14:44:58 +0200
Subject: [PATCH 26/58] render proper welcome hero text

---
 src/components/ReportWelcomeText.tsx | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/components/ReportWelcomeText.tsx b/src/components/ReportWelcomeText.tsx
index 24d7747a8fc7..77c40354ea80 100644
--- a/src/components/ReportWelcomeText.tsx
+++ b/src/components/ReportWelcomeText.tsx
@@ -59,6 +59,10 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP
     };
 
     const welcomeHeroText = useMemo(() => {
+        if (isInvoiceRoom) {
+            return translate('reportActionsView.sayHello');
+        }
+
         if (isChatRoom) {
             return translate('reportActionsView.welcomeToRoom', {roomName: reportName});
         }
@@ -68,7 +72,7 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP
         }
 
         return translate('reportActionsView.sayHello');
-    }, [isChatRoom, isSelfDM, translate, reportName]);
+    }, [isChatRoom, isInvoiceRoom, isSelfDM, translate, reportName]);
 
     return (
         <>

From 60462fd0c3af94813877902a069446633bb3f318 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Mon, 15 Apr 2024 15:35:31 +0200
Subject: [PATCH 27/58] render proper invoice room title

---
 src/libs/ReportUtils.ts         | 29 ++++++++++++++++++++---------
 src/pages/home/ReportScreen.tsx |  2 ++
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 8305e90d20d3..c8163a5e2947 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -2983,19 +2983,30 @@ function getReportActionMessage(reportAction: ReportAction | EmptyObject, parent
 /**
  * Get the title for an invoice room.
  */
-function getInvoicesChatName(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>): string {
-    const policyName = getPolicyName(report, false, policy);
-    let receiverName = '';
+function getInvoicesChatName(report: OnyxEntry<Report>): string {
+    const invoiceReceiver = report?.invoiceReceiver;
+    const isIndividual = invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
+    const invoiceReceiverAccountID = isIndividual ? invoiceReceiver.accountID : -1;
+    const policyID = isIndividual ? '' : invoiceReceiver?.policyID ?? '';
+    let isReceiver = false;
+
+    if (isIndividual && invoiceReceiverAccountID === currentUserAccountID) {
+        isReceiver = true;
+    }
+
+    if (!isIndividual && PolicyUtils.isPolicyMember(policyID, allPolicies)) {
+        isReceiver = true;
+    }
 
-    if (report?.invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL) {
-        receiverName = PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[report.invoiceReceiver.accountID]);
+    if (isReceiver) {
+        return getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]);
     }
 
-    if (report?.invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.POLICY) {
-        receiverName = getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report.invoiceReceiver.policyID}`]);
+    if (isIndividual) {
+        return PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[invoiceReceiverAccountID]);
     }
 
-    return `${receiverName} & ${policyName}`;
+    return getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]);
 }
 
 /**
@@ -3070,7 +3081,7 @@ function getReportName(report: OnyxEntry<Report>, policy: OnyxEntry<Policy> = nu
     }
 
     if (isInvoiceRoom(report)) {
-        formattedName = getInvoicesChatName(report, policy);
+        formattedName = getInvoicesChatName(report);
     }
 
     if (formattedName) {
diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx
index 7e31b69779c2..0f32c6a8b5dc 100644
--- a/src/pages/home/ReportScreen.tsx
+++ b/src/pages/home/ReportScreen.tsx
@@ -204,6 +204,7 @@ function ReportScreen({
             isOptimisticReport: reportProp?.isOptimisticReport,
             lastMentionedTime: reportProp?.lastMentionedTime,
             avatarUrl: reportProp?.avatarUrl,
+            invoiceReceiver: reportProp?.invoiceReceiver,
         }),
         [
             reportProp?.lastReadTime,
@@ -243,6 +244,7 @@ function ReportScreen({
             reportProp?.isOptimisticReport,
             reportProp?.lastMentionedTime,
             reportProp?.avatarUrl,
+            reportProp?.invoiceReceiver,
         ],
     );
 

From a524346f9402a98b9b6900a167c9ca15a1569078 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Mon, 15 Apr 2024 15:53:33 +0200
Subject: [PATCH 28/58] integrate report subtitle for invoice room

---
 src/languages/en.ts     |  4 ++++
 src/languages/es.ts     |  4 ++++
 src/languages/types.ts  |  6 ++++++
 src/libs/ReportUtils.ts | 39 ++++++++++++++++++++++++++++++++++++---
 4 files changed, 50 insertions(+), 3 deletions(-)

diff --git a/src/languages/en.ts b/src/languages/en.ts
index b38601420c2d..275d578b8813 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -30,6 +30,8 @@ import type {
     GoBackMessageParams,
     GoToRoomParams,
     InstantSummaryParams,
+    InvoicesFromParams,
+    InvoicesToParams,
     LocalTimeParams,
     LoggedInAsParams,
     LogSizeParams,
@@ -2144,6 +2146,8 @@ export default {
             unlockVBACopy: "You're all set to accept payments by ACH or credit card!",
             viewUnpaidInvoices: 'View unpaid invoices',
             sendInvoice: 'Send invoice',
+            invoicesFrom: ({sender}: InvoicesFromParams) => `Invoices from ${sender}`,
+            invoicesTo: ({receiver}: InvoicesToParams) => `Invoices to ${receiver}`,
         },
         travel: {
             unlockConciergeBookingTravel: 'Unlock Concierge travel booking',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 2263170425c3..0ed33dd533a6 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -29,6 +29,8 @@ import type {
     GoBackMessageParams,
     GoToRoomParams,
     InstantSummaryParams,
+    InvoicesFromParams,
+    InvoicesToParams,
     LocalTimeParams,
     LoggedInAsParams,
     LogSizeParams,
@@ -2172,6 +2174,8 @@ export default {
             unlockVBACopy: '¡Todo listo para recibir pagos por transferencia o con tarjeta!',
             viewUnpaidInvoices: 'Ver facturas emitidas pendientes',
             sendInvoice: 'Enviar factura',
+            invoicesFrom: ({sender}: InvoicesFromParams) => `Facturas de ${sender}`,
+            invoicesTo: ({receiver}: InvoicesToParams) => `Facturas a ${receiver}`,
         },
         travel: {
             unlockConciergeBookingTravel: 'Desbloquea la reserva de viajes con Concierge',
diff --git a/src/languages/types.ts b/src/languages/types.ts
index 59e1bfe40af2..8c4d287b7dfc 100644
--- a/src/languages/types.ts
+++ b/src/languages/types.ts
@@ -251,6 +251,10 @@ type ViolationsTaxOutOfPolicyParams = {taxName?: string};
 
 type TaskCreatedActionParams = {title: string};
 
+type InvoicesFromParams = {sender: string};
+
+type InvoicesToParams = {receiver: string};
+
 /* Translation Object types */
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 type TranslationBaseValue = string | string[] | ((...args: any[]) => string);
@@ -403,4 +407,6 @@ export type {
     ZipCodeExampleFormatParams,
     LogSizeParams,
     HeldRequestParams,
+    InvoicesFromParams,
+    InvoicesToParams,
 };
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index c8163a5e2947..db20ba2a45c3 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -3009,6 +3009,39 @@ function getInvoicesChatName(report: OnyxEntry<Report>): string {
     return getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]);
 }
 
+/**
+ * Get the subtitle for an invoice room.
+ */
+function getInvoicesChatSubtitle(report: OnyxEntry<Report>): string {
+    const invoiceReceiver = report?.invoiceReceiver;
+    const isIndividual = invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
+    const invoiceReceiverAccountID = isIndividual ? invoiceReceiver.accountID : -1;
+    const policyID = isIndividual ? '' : invoiceReceiver?.policyID ?? '';
+    let isReceiver = false;
+
+    if (isIndividual && invoiceReceiverAccountID === currentUserAccountID) {
+        isReceiver = true;
+    }
+
+    if (!isIndividual && PolicyUtils.isPolicyMember(policyID, allPolicies)) {
+        isReceiver = true;
+    }
+
+    if (isReceiver) {
+        let receiver = '';
+
+        if (isIndividual) {
+            receiver = PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[invoiceReceiverAccountID]);
+        } else {
+            receiver = getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${invoiceReceiver?.policyID}`]);
+        }
+
+        return Localize.translateLocal('workspace.invoices.invoicesTo', {receiver});
+    }
+
+    return Localize.translateLocal('workspace.invoices.invoicesFrom', {sender: getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`])});
+}
+
 /**
  * Get the title for a report.
  */
@@ -3102,6 +3135,9 @@ function getReportName(report: OnyxEntry<Report>, policy: OnyxEntry<Policy> = nu
  * Get either the policyName or domainName the chat is tied to
  */
 function getChatRoomSubtitle(report: OnyxEntry<Report>): string | undefined {
+    if (isInvoiceRoom(report)) {
+        return getInvoicesChatSubtitle(report);
+    }
     if (isChatThread(report)) {
         return '';
     }
@@ -3118,9 +3154,6 @@ function getChatRoomSubtitle(report: OnyxEntry<Report>): string | undefined {
     if (isArchivedRoom(report)) {
         return report?.oldPolicyName ?? '';
     }
-    if (isInvoiceRoom(report)) {
-        return Localize.translateLocal('workspace.common.invoices');
-    }
     return getPolicyName(report);
 }
 

From 933499e25c29b7708abe7008f6d014e24a7b5545 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Mon, 15 Apr 2024 16:05:15 +0200
Subject: [PATCH 29/58] integrate payer name

---
 src/components/MoneyReportHeader.tsx              |  9 +++------
 src/components/ReportActionItem/ReportPreview.tsx |  9 +++------
 src/libs/ReportUtils.ts                           | 13 +++++++++++++
 3 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx
index befcaf470901..4f66d3f959b4 100644
--- a/src/components/MoneyReportHeader.tsx
+++ b/src/components/MoneyReportHeader.tsx
@@ -102,6 +102,8 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money
 
     const shouldShowWaitingNote = ReportUtils.isInvoiceAwaitingPayment(moneyRequestReport);
 
+    const invoicePayerName = ReportUtils.getInvoicePayerName(chatReport);
+
     const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0;
     const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport);
     const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE;
@@ -266,12 +268,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money
                         <MoneyReportHeaderStatusBar nextStep={nextStep} />
                     </View>
                 )}
-                {shouldShowWaitingNote && (
-                    <PaymentWaitingBanner
-                        // TODO: Integrate a getter for the payer name
-                        payerName=""
-                    />
-                )}
+                {shouldShowWaitingNote && <PaymentWaitingBanner payerName={invoicePayerName} />}
             </View>
             {isHoldMenuVisible && requestType !== undefined && (
                 <ProcessMoneyReportHoldMenu
diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx
index 9ff09ad33ec9..dad91b570311 100644
--- a/src/components/ReportActionItem/ReportPreview.tsx
+++ b/src/components/ReportActionItem/ReportPreview.tsx
@@ -218,6 +218,8 @@ function ReportPreview({
 
     const shouldShowWaitingNote = ReportUtils.isInvoiceAwaitingPayment(iouReport);
 
+    const invoicePayerName = ReportUtils.getInvoicePayerName(chatReport);
+
     /*
      Show subtitle if at least one of the money requests is not being smart scanned, and either:
      - There is more than one money request – in this case, the "X requests, Y scanning" subtitle is shown;
@@ -355,12 +357,7 @@ function ReportPreview({
                                         isDisabled={shouldDisableSubmitButton}
                                     />
                                 )}
-                                {shouldShowWaitingNote && (
-                                    <PaymentWaitingBanner
-                                        // TODO: Integrate a getter for the payer name
-                                        payerName=""
-                                    />
-                                )}
+                                {shouldShowWaitingNote && <PaymentWaitingBanner payerName={invoicePayerName} />}
                             </View>
                         </View>
                     </View>
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index db20ba2a45c3..d4d85be0d933 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -2964,6 +2964,17 @@ function getAdminRoomInvitedParticipants(parentReportAction: ReportAction | Reco
     return roomName ? `${verb} ${users} ${preposition} ${roomName}` : `${verb} ${users}`;
 }
 
+function getInvoicePayerName(report: OnyxEntry<Report>): string {
+    const invoiceReceiver = report?.invoiceReceiver;
+    const isIndividual = invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
+
+    if (isIndividual) {
+        return PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[invoiceReceiver.accountID]);
+    }
+
+    return getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${invoiceReceiver?.policyID}`]);
+}
+
 /**
  * Get the report action message for a report action.
  */
@@ -6078,7 +6089,9 @@ export {
     getIcons,
     getRoomWelcomeMessage,
     getDisplayNamesWithTooltips,
+    getInvoicePayerName,
     getInvoicesChatName,
+    getInvoicesChatSubtitle,
     getReportName,
     getReport,
     getReportNotificationPreference,

From 80dbeef598dae218b7d43d238701478c8f61651b Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Mon, 15 Apr 2024 16:28:01 +0200
Subject: [PATCH 30/58] render proper actor of invoice

---
 src/pages/home/report/ReportActionItemSingle.tsx | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx
index 1e0dc432b3fc..7d0b22b22f52 100644
--- a/src/pages/home/report/ReportActionItemSingle.tsx
+++ b/src/pages/home/report/ReportActionItemSingle.tsx
@@ -84,8 +84,11 @@ function ReportActionItemSingle({
     const {avatar, login, pendingFields, status, fallbackIcon} = personalDetails[actorAccountID ?? -1] ?? {};
     // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
     let actorHint = (login || (displayName ?? '')).replace(CONST.REGEX.MERGED_ACCOUNT_PREFIX, '');
-    const displayAllActors = useMemo(() => action?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && iouReport, [action?.actionName, iouReport]);
-    const isWorkspaceActor = ReportUtils.isPolicyExpenseChat(report) && (!actorAccountID || displayAllActors);
+    const displayAllActors = useMemo(
+        () => action?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && iouReport && !ReportUtils.isInvoiceReport(iouReport),
+        [action?.actionName, iouReport],
+    );
+    const isWorkspaceActor = ReportUtils.isInvoiceReport(iouReport ?? {}) || (ReportUtils.isPolicyExpenseChat(report) && (!actorAccountID || displayAllActors));
     let avatarSource = UserUtils.getAvatar(avatar ?? '', actorAccountID);
 
     if (isWorkspaceActor) {

From 2f5a0be8a68191c54b94c1c9abbbfda789f67304 Mon Sep 17 00:00:00 2001
From: VickyStash <vikstash@gmail.com>
Date: Tue, 16 Apr 2024 16:55:12 +0200
Subject: [PATCH 31/58] Support one transaction view for invoices

---
 src/components/MoneyReportHeader.tsx |  8 ++++++--
 src/libs/ReportActionsUtils.ts       |  2 +-
 src/libs/ReportUtils.ts              | 15 +++++++++++++--
 3 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx
index 4f66d3f959b4..dbc73973c274 100644
--- a/src/components/MoneyReportHeader.tsx
+++ b/src/components/MoneyReportHeader.tsx
@@ -193,7 +193,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money
                 shouldShowBackButton={isSmallScreenWidth}
                 onBackButtonPress={() => Navigation.goBack(undefined, false, true)}
                 // Shows border if no buttons or next steps are showing below the header
-                shouldShowBorderBottom={!(shouldShowAnyButton && isSmallScreenWidth) && !(shouldShowNextStep && !isSmallScreenWidth)}
+                shouldShowBorderBottom={!(shouldShowAnyButton && isSmallScreenWidth) && !(shouldShowNextStep && !isSmallScreenWidth) && !shouldShowWaitingNote}
                 shouldShowThreeDotsButton
                 threeDotsMenuItems={threeDotsMenuItems}
                 threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(windowWidth)}
@@ -268,7 +268,11 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money
                         <MoneyReportHeaderStatusBar nextStep={nextStep} />
                     </View>
                 )}
-                {shouldShowWaitingNote && <PaymentWaitingBanner payerName={invoicePayerName} />}
+                {shouldShowWaitingNote && (
+                    <View style={[styles.ph5, styles.pb3]}>
+                        <PaymentWaitingBanner payerName={invoicePayerName} />
+                    </View>
+                )}
             </View>
             {isHoldMenuVisible && requestType !== undefined && (
                 <ProcessMoneyReportHoldMenu
diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index e8f2189f5f7d..21aa31f39bb8 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -228,7 +228,7 @@ function isTransactionThread(parentReportAction: OnyxEntry<ReportAction> | Empty
 function getOneTransactionThreadReportID(reportID: string, reportActions: OnyxEntry<ReportActions> | ReportAction[]): string | null {
     // If the report is not an IOU or Expense report, it shouldn't be treated as one-transaction report.
     const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
-    if (report?.type !== CONST.REPORT.TYPE.IOU && report?.type !== CONST.REPORT.TYPE.EXPENSE) {
+    if (report?.type !== CONST.REPORT.TYPE.IOU && report?.type !== CONST.REPORT.TYPE.EXPENSE && report?.type !== CONST.REPORT.TYPE.INVOICE) {
         return null;
     }
 
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index d4d85be0d933..630f6f70c093 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -920,6 +920,13 @@ function isInvoiceReport(report: OnyxEntry<Report> | EmptyObject): boolean {
     return report?.type === CONST.REPORT.TYPE.INVOICE;
 }
 
+/**
+ * Checks if the supplied report is an invoice report in Open state and status.
+ */
+function isOpenInvoiceReport(report: OnyxEntry<Report> | EmptyObject): boolean {
+    return isInvoiceReport(report) && report?.stateNum === CONST.REPORT.STATE_NUM.OPEN && report?.statusNum === CONST.REPORT.STATUS_NUM.OPEN;
+}
+
 /**
  * Whether the provided report is a chat room
  */
@@ -2414,7 +2421,7 @@ function getMoneyRequestReportName(report: OnyxEntry<Report>, policy: OnyxEntry<
         return Localize.translateLocal('iou.payerSpentAmount', {payer: payerOrApproverName, amount: formattedAmount});
     }
 
-    if (isProcessingReport(report) || isOpenExpenseReport(report) || moneyRequestTotal === 0) {
+    if (isProcessingReport(report) || isOpenExpenseReport(report) || isOpenInvoiceReport(report) || moneyRequestTotal === 0) {
         return Localize.translateLocal('iou.payerOwesAmount', {payer: payerOrApproverName, amount: formattedAmount});
     }
 
@@ -3112,7 +3119,7 @@ function getReportName(report: OnyxEntry<Report>, policy: OnyxEntry<Policy> = nu
         formattedName = getPolicyExpenseChatName(report, policy);
     }
 
-    if (isMoneyRequestReport(report)) {
+    if (isMoneyRequestReport(report) || isInvoiceReport(report)) {
         formattedName = getMoneyRequestReportName(report, policy);
     }
 
@@ -3185,6 +3192,10 @@ function getParentNavigationSubtitle(report: OnyxEntry<Report>): ParentNavigatio
         return {};
     }
 
+    if (isInvoiceReport(report)) {
+        return {reportName: `${getPolicyName(parentReport)} & ${getInvoicePayerName(parentReport)}`};
+    }
+
     return {
         reportName: getReportName(parentReport),
         workspaceName: getPolicyName(parentReport, true),

From 875d321e48b2cb0e3518ca5891ec704107f2f27f Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Tue, 16 Apr 2024 17:34:09 +0200
Subject: [PATCH 32/58] restrict room leaving

---
 src/libs/ReportUtils.ts | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 630f6f70c093..ec34ae404606 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -5155,10 +5155,31 @@ function getMoneyRequestOptions(report: OnyxEntry<Report>, policy: OnyxEntry<Pol
  * `invoice` - Invoice sender, invoice receiver and auto-invited admins cannot leave
  */
 function canLeaveRoom(report: OnyxEntry<Report>, isPolicyMember: boolean): boolean {
-    if (report?.chatType === CONST.REPORT.CHAT_TYPE.INVOICE) {
-        const isAdmin = !!Object.entries(report.participants ?? {}).find(([participantID, {role}]) => Number(participantID) === currentUserAccountID && role !== CONST.POLICY.ROLE.ADMIN);
+    if (isInvoiceRoom(report)) {
+        const invoiceReport = getReport(report?.iouReportID ?? '');
+
+        if (invoiceReport?.ownerAccountID === currentUserAccountID) {
+            return false;
+        }
+
+        if (invoiceReport?.managerID === currentUserAccountID) {
+            return false;
+        }
+
+        const isSenderPolicyAdmin = getPolicy(report?.policyID)?.role === CONST.POLICY.ROLE.ADMIN;
 
-        return report.managerID !== currentUserAccountID && report.ownerAccountID !== currentUserAccountID && !isAdmin;
+        if (isSenderPolicyAdmin) {
+            return false;
+        }
+
+        const isReceiverPolicyAdmin =
+            report?.invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.POLICY ? getPolicy(report?.invoiceReceiver?.policyID)?.role === CONST.POLICY.ROLE.ADMIN : false;
+
+        if (isReceiverPolicyAdmin) {
+            return false;
+        }
+
+        return true;
     }
 
     if (!report?.visibility) {

From babdb9acb0882a7e82959539d8b14dd1042af360 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Tue, 16 Apr 2024 18:05:46 +0200
Subject: [PATCH 33/58] configure ReportDetailsPage for invoices

---
 src/libs/ReportUtils.ts         | 28 ++++++++++++++++------------
 src/pages/ReportDetailsPage.tsx | 24 +++++++++++++-----------
 2 files changed, 29 insertions(+), 23 deletions(-)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index ec34ae404606..77c177bcee9a 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -1964,21 +1964,23 @@ function getIcons(
         return [groupChatIcon];
     }
 
-    if (isInvoiceRoom(report)) {
-        const workspaceIcon = getWorkspaceIcon(report, policy);
+    if (isInvoiceReport(report)) {
+        const invoiceRoomReport = getReport(report.chatReportID);
+        const icons = [getWorkspaceIcon(invoiceRoomReport, policy)];
 
-        const receiverPolicyID = Object.values(report.participants ?? {})?.find((participant) => participant.type === 'policy')?.policyID ?? '';
-        const receiverPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${receiverPolicyID}`];
-        const isWorkspaceToWorkspace = !!receiverPolicyID && receiverPolicy;
-        const icons = [];
+        if (invoiceRoomReport?.invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL) {
+            icons.push(...getIconsForParticipants([invoiceRoomReport?.invoiceReceiver.accountID], personalDetails));
 
-        if (isWorkspaceToWorkspace) {
-            icons.push(getWorkspaceIcon(report, receiverPolicy));
-        } else {
-            icons.push(...getIconsForParticipants(report?.participantAccountIDs ?? [], personalDetails));
+            return icons;
         }
 
-        return [workspaceIcon, ...icons];
+        const receiverPolicy = getPolicy(invoiceRoomReport?.invoiceReceiver?.policyID);
+
+        if (!isEmptyObject(receiverPolicy)) {
+            icons.push(getWorkspaceIcon(invoiceRoomReport, receiverPolicy));
+        }
+
+        return icons;
     }
 
     return getIconsForParticipants(report?.participantAccountIDs ?? [], personalDetails);
@@ -5642,7 +5644,9 @@ function isReportParticipant(accountID: number, report: OnyxEntry<Report>): bool
 }
 
 function shouldUseFullTitleToDisplay(report: OnyxEntry<Report>): boolean {
-    return isMoneyRequestReport(report) || isPolicyExpenseChat(report) || isChatRoom(report) || isChatThread(report) || isTaskReport(report) || isGroupChat(report);
+    return (
+        isMoneyRequestReport(report) || isPolicyExpenseChat(report) || isChatRoom(report) || isChatThread(report) || isTaskReport(report) || isGroupChat(report) || isInvoiceReport(report)
+    );
 }
 
 function getRoom(type: ValueOf<typeof CONST.REPORT.CHAT_TYPE>, policyID: string): OnyxEntry<Report> | undefined {
diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx
index 7f1dadab8c0e..048b1215787f 100644
--- a/src/pages/ReportDetailsPage.tsx
+++ b/src/pages/ReportDetailsPage.tsx
@@ -75,6 +75,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
     const isChatThread = useMemo(() => ReportUtils.isChatThread(report), [report]);
     const isArchivedRoom = useMemo(() => ReportUtils.isArchivedRoom(report), [report]);
     const isMoneyRequestReport = useMemo(() => ReportUtils.isMoneyRequestReport(report), [report]);
+    const isInvoiceReport = useMemo(() => ReportUtils.isInvoiceReport(report), [report]);
     const canEditReportDescription = useMemo(() => ReportUtils.canEditReportDescription(report, policy), [report, policy]);
     const shouldShowReportDescription = isChatRoom && (canEditReportDescription || report.description !== '');
 
@@ -182,7 +183,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
         });
 
         // Prevent displaying private notes option for threads and task reports
-        if (!isChatThread && !isMoneyRequestReport && !ReportUtils.isTaskReport(report)) {
+        if (!isChatThread && !isMoneyRequestReport && !isInvoiceReport && !ReportUtils.isTaskReport(report)) {
             items.push({
                 key: CONST.REPORT_DETAILS_MENU_ITEM.PRIVATE_NOTES,
                 translationKey: 'privateNotes.title',
@@ -195,19 +196,20 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
 
         return items;
     }, [
+        isSelfDM,
+        isGroupDMChat,
         isArchivedRoom,
-        participants.length,
+        isGroupChat,
+        isDefaultRoom,
         isChatThread,
-        isMoneyRequestReport,
-        report,
-        isGroupDMChat,
         isPolicyMember,
         isUserCreatedPolicyRoom,
-        session,
-        isSelfDM,
-        isDefaultRoom,
+        participants.length,
+        report,
+        isMoneyRequestReport,
+        isInvoiceReport,
         activeChatMembers.length,
-        isGroupChat,
+        session,
     ]);
 
     const displayNamesWithTooltips = useMemo(() => {
@@ -261,7 +263,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
                 <ScrollView style={[styles.flex1]}>
                     <View style={styles.reportDetailsTitleContainer}>
                         <View style={styles.mb3}>
-                            {isMoneyRequestReport ? (
+                            {isMoneyRequestReport || isInvoiceReport ? (
                                 <MultipleAvatars
                                     icons={icons}
                                     size={CONST.AVATAR_SIZE.LARGE}
@@ -297,7 +299,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
                             ) : (
                                 chatRoomSubtitleText
                             )}
-                            {!isEmptyObject(parentNavigationSubtitleData) && isMoneyRequestReport && (
+                            {!isEmptyObject(parentNavigationSubtitleData) && (isMoneyRequestReport || isInvoiceReport) && (
                                 <ParentNavigationSubtitle
                                     parentNavigationSubtitleData={parentNavigationSubtitleData}
                                     parentReportID={report?.parentReportID}

From 62303174cfc4738766247b36640082a7e7c767b6 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Tue, 16 Apr 2024 19:00:21 +0200
Subject: [PATCH 34/58] check if the user can pay an invoice

---
 src/libs/actions/IOU.ts | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts
index 85f4b74f3436..e98fac17bee8 100644
--- a/src/libs/actions/IOU.ts
+++ b/src/libs/actions/IOU.ts
@@ -4857,6 +4857,14 @@ function canIOUBePaid(iouReport: OnyxEntry<OnyxTypes.Report> | EmptyObject, chat
         return false;
     }
 
+    if (ReportUtils.isInvoiceReport(iouReport)) {
+        if (chatReport?.invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL) {
+            return chatReport?.invoiceReceiver?.accountID === userAccountID;
+        }
+
+        return getPolicy(chatReport?.invoiceReceiver?.policyID).role === CONST.POLICY.ROLE.ADMIN;
+    }
+
     const isPayer = ReportUtils.isPayer(
         {
             email: currentUserEmail,

From 23dd180b89f7b656b5c2138b49bac1c0a1a4c3ac Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 17 Apr 2024 11:48:47 +0200
Subject: [PATCH 35/58] improve getInvoicesChatName

---
 src/libs/ReportUtils.ts | 20 +++++++-------------
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 28edbd79a9ba..4f50562de698 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -3011,26 +3011,20 @@ function getInvoicesChatName(report: OnyxEntry<Report>): string {
     const invoiceReceiver = report?.invoiceReceiver;
     const isIndividual = invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
     const invoiceReceiverAccountID = isIndividual ? invoiceReceiver.accountID : -1;
-    const policyID = isIndividual ? '' : invoiceReceiver?.policyID ?? '';
-    let isReceiver = false;
-
-    if (isIndividual && invoiceReceiverAccountID === currentUserAccountID) {
-        isReceiver = true;
-    }
+    const invoiceReceiverPolicyID = isIndividual ? '' : invoiceReceiver?.policyID ?? '';
+    const isCurrentUserReceiver =
+        (isIndividual && invoiceReceiverAccountID === currentUserAccountID) || (!isIndividual && PolicyUtils.isPolicyEmployee(invoiceReceiverPolicyID, allPolicies));
 
-    if (!isIndividual && PolicyUtils.isPolicyEmployee(policyID, allPolicies)) {
-        isReceiver = true;
-    }
-
-    if (isReceiver) {
-        return getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]);
+    if (isCurrentUserReceiver) {
+        return getPolicyName(report);
     }
 
     if (isIndividual) {
         return PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[invoiceReceiverAccountID]);
     }
 
-    return getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]);
+    // TODO: Check this flow in a scope of the Invoice V0.3
+    return getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${invoiceReceiverPolicyID}`]);
 }
 
 /**

From 12bd9c484f46510441726eb5626cb974153b6f5b Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 17 Apr 2024 11:52:24 +0200
Subject: [PATCH 36/58] add comment

---
 src/libs/ReportUtils.ts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 4f50562de698..8a0b1d43adf6 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -2977,6 +2977,11 @@ function getAdminRoomInvitedParticipants(parentReportAction: ReportAction | Reco
     return roomName ? `${verb} ${users} ${preposition} ${roomName}` : `${verb} ${users}`;
 }
 
+/**
+ * Get the invoice payer name based on its type:
+ * - Individual - a receiver display name.
+ * - Policy - a receiver policy name.
+ */
 function getInvoicePayerName(report: OnyxEntry<Report>): string {
     const invoiceReceiver = report?.invoiceReceiver;
     const isIndividual = invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL;

From 7b711429ea0a4ff3a965b531a7097aacd3e945bc Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 17 Apr 2024 11:53:03 +0200
Subject: [PATCH 37/58] Revert "integrate deleted invoice message"

This reverts commit 4e81a6c86a7a00ffbaa7692f17cf82d29f0cfb24.
---
 src/components/ReportActionItem/MoneyRequestAction.tsx | 2 --
 src/languages/en.ts                                    | 1 -
 src/languages/es.ts                                    | 1 -
 src/pages/home/report/ReportActionItem.tsx             | 2 --
 4 files changed, 6 deletions(-)

diff --git a/src/components/ReportActionItem/MoneyRequestAction.tsx b/src/components/ReportActionItem/MoneyRequestAction.tsx
index 9bef637bf292..7d9ba2697c7a 100644
--- a/src/components/ReportActionItem/MoneyRequestAction.tsx
+++ b/src/components/ReportActionItem/MoneyRequestAction.tsx
@@ -116,8 +116,6 @@ function MoneyRequestAction({
             message = 'parentReportAction.reversedTransaction';
         } else if (isTrackExpenseAction) {
             message = 'parentReportAction.deletedExpense';
-        } else if (action.childType === CONST.REPORT.TYPE.INVOICE) {
-            message = 'parentReportAction.deletedInvoice';
         } else {
             message = 'parentReportAction.deletedRequest';
         }
diff --git a/src/languages/en.ts b/src/languages/en.ts
index b6de47a3aaf0..05313113c521 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -2541,7 +2541,6 @@ export default {
         reversedTransaction: '[Reversed transaction]',
         deletedTask: '[Deleted task]',
         hiddenMessage: '[Hidden message]',
-        deletedInvoice: '[Deleted invoice]',
     },
     threads: {
         thread: 'Thread',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 6b963a874599..f99eaa4eef10 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -3033,7 +3033,6 @@ export default {
         reversedTransaction: '[Transacción anulada]',
         deletedTask: '[Tarea eliminada]',
         hiddenMessage: '[Mensaje oculto]',
-        deletedInvoice: '[Factura eliminada]',
     },
     threads: {
         thread: 'Hilo',
diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx
index 06e222d86928..6a6eca9fb734 100644
--- a/src/pages/home/report/ReportActionItem.tsx
+++ b/src/pages/home/report/ReportActionItem.tsx
@@ -738,8 +738,6 @@ function ReportActionItem({
                     message = 'parentReportAction.reversedTransaction';
                 } else if (ReportActionsUtils.isTrackExpenseAction(parentReportAction)) {
                     message = 'parentReportAction.deletedExpense';
-                } else if (parentReportAction?.childType === CONST.REPORT.TYPE.INVOICE) {
-                    message = 'parentReportAction.deletedInvoice';
                 } else {
                     message = 'parentReportAction.deletedRequest';
                 }

From 78f5f642773d697474736dbe2cbcf4eea6384d8b Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 17 Apr 2024 11:54:01 +0200
Subject: [PATCH 38/58] Revert "integrate deleted invoice message in
 getTransactionReportName"

This reverts commit 19b54e34b25b9d9ddcb7c27ae4b237cdcac744ff.
---
 src/libs/ReportUtils.ts | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 8a0b1d43adf6..4f8a16246d61 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -191,9 +191,6 @@ type OptimisticIOUReportAction = Pick<
     | 'receipt'
     | 'whisperedToAccountIDs'
     | 'childReportID'
-    | 'childType'
-    | 'childVisibleActionCount'
-    | 'childCommenterCount'
 >;
 
 type ReportRouteParams = {
@@ -2691,10 +2688,6 @@ function getTransactionReportName(reportAction: OnyxEntry<ReportAction | Optimis
         return Localize.translateLocal('iou.receiptMissingDetails');
     }
 
-    if (reportAction?.childType === CONST.REPORT.TYPE.INVOICE) {
-        return Localize.translateLocal('parentReportAction.deletedInvoice');
-    }
-
     const transactionDetails = getTransactionDetails(transaction);
 
     return Localize.translateLocal(ReportActionsUtils.isSentMoneyReportAction(reportAction) ? 'iou.threadSentMoneyReportName' : 'iou.threadRequestReportName', {

From c230799834047354b45cda6f0f00b1d24cafded4 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 17 Apr 2024 11:54:30 +0200
Subject: [PATCH 39/58] clear redundant participant props

---
 src/types/onyx/Report.ts | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts
index 2bad31bc372c..36f124a4b826 100644
--- a/src/types/onyx/Report.ts
+++ b/src/types/onyx/Report.ts
@@ -26,9 +26,6 @@ type PendingChatMember = {
 type Participant = {
     hidden?: boolean;
     role?: 'admin' | 'member';
-    // TODO: Confirm
-    type?: 'policy' | 'individual';
-    policyID?: string;
 };
 
 type Participants = Record<number, Participant>;

From 5625582f11ab9b8a4c136651fce4319b09ad6689 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 17 Apr 2024 12:16:41 +0200
Subject: [PATCH 40/58] sync changes

---
 src/CONST.ts             |  3 ++-
 src/languages/en.ts      |  2 +-
 src/languages/es.ts      |  2 +-
 src/libs/ReportUtils.ts  | 32 +++++++++++++++++---------------
 src/types/onyx/Report.ts | 23 +++++++++++++----------
 5 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/src/CONST.ts b/src/CONST.ts
index 0dbf26851ead..95056970457b 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -52,7 +52,7 @@ const chatTypes = {
     POLICY_ROOM: 'policyRoom',
     POLICY_EXPENSE_CHAT: 'policyExpenseChat',
     SELF_DM: 'selfDM',
-    INVOICE: 'invoiceRoom',
+    INVOICE: 'invoice',
 } as const;
 
 // Explicit type annotation is required
@@ -1423,6 +1423,7 @@ const CONST = {
             SPLIT: 'split',
             REQUEST: 'request',
             TRACK_EXPENSE: 'track-expense',
+            INVOICE: 'invoice',
         },
         REQUEST_TYPE: {
             DISTANCE: 'distance',
diff --git a/src/languages/en.ts b/src/languages/en.ts
index 05313113c521..f9c845b42a5a 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -505,6 +505,7 @@ export default {
         beginningOfChatHistoryAnnounceRoomPartTwo: ({workspaceName}: BeginningOfChatHistoryAnnounceRoomPartTwo) => ` to chat about anything ${workspaceName} related.`,
         beginningOfChatHistoryUserRoomPartOne: 'Collaboration starts here! 🎉\nUse this space to chat about anything ',
         beginningOfChatHistoryUserRoomPartTwo: ' related.',
+        beginningOfChatHistoryInvoiceRoom: 'Collaboration starts here! 🎉 Use this room to view, discuss, and pay invoices.',
         beginningOfChatHistory: 'This is the beginning of your chat with ',
         beginningOfChatHistoryPolicyExpenseChatPartOne: 'Collaboration between ',
         beginningOfChatHistoryPolicyExpenseChatPartTwo: ' and ',
@@ -522,7 +523,6 @@ export default {
             // eslint-disable-next-line @typescript-eslint/naming-convention
             'track-expense': 'track an expense',
         },
-        beginningOfChatHistoryInvoiceRoom: 'Collaboration starts here! 🎉 \nUse this room to view, discuss, and pay invoices.',
     },
     reportAction: {
         asCopilot: 'as copilot for',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index f99eaa4eef10..568e14e6b241 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -501,6 +501,7 @@ export default {
         beginningOfChatHistoryAnnounceRoomPartTwo: ({workspaceName}: BeginningOfChatHistoryAnnounceRoomPartTwo) => ` para chatear sobre cualquier cosa relacionada con ${workspaceName}.`,
         beginningOfChatHistoryUserRoomPartOne: '¡Este es el lugar para colaborar! 🎉\nUsa este espacio para chatear sobre cualquier cosa relacionada con ',
         beginningOfChatHistoryUserRoomPartTwo: '.',
+        beginningOfChatHistoryInvoiceRoom: '¡Este es el lugar para colaborar! 🎉 Utilice esta sala para ver, discutir y pagar facturas.',
         beginningOfChatHistory: 'Aquí comienzan tus conversaciones con ',
         beginningOfChatHistoryPolicyExpenseChatPartOne: '¡La colaboración entre ',
         beginningOfChatHistoryPolicyExpenseChatPartTwo: ' y ',
@@ -518,7 +519,6 @@ export default {
             // eslint-disable-next-line @typescript-eslint/naming-convention
             'track-expense': 'rastrear un gasto',
         },
-        beginningOfChatHistoryInvoiceRoom: '¡Este es el lugar para colaborar! 🎉\nUsa esta sala para ver, discutir y pagar facturas.',
     },
     reportAction: {
         asCopilot: 'como copiloto de',
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 4f8a16246d61..76693877b462 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -141,6 +141,7 @@ type OptimisticAddCommentReportAction = Pick<
     | 'childStatusNum'
     | 'childStateNum'
     | 'errors'
+    | 'whisperedToAccountIDs'
 > & {isOptimisticAction: boolean};
 
 type OptimisticReportAction = {
@@ -283,6 +284,7 @@ type OptimisticChatReport = Pick<
     | 'description'
     | 'writeCapability'
     | 'avatarUrl'
+    | 'invoiceReceiver'
 > & {
     isOptimisticReport: true;
 };
@@ -675,6 +677,13 @@ function isChatReport(report: OnyxEntry<Report> | EmptyObject): boolean {
     return report?.type === CONST.REPORT.TYPE.CHAT;
 }
 
+/**
+ * Checks if a report is an invoice report.
+ */
+function isInvoiceReport(report: OnyxEntry<Report> | EmptyObject): boolean {
+    return report?.type === CONST.REPORT.TYPE.INVOICE;
+}
+
 /**
  * Checks if a report is an Expense report.
  */
@@ -862,6 +871,13 @@ function isPolicyExpenseChat(report: OnyxEntry<Report> | Participant | EmptyObje
     return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT || (report?.isPolicyExpenseChat ?? false);
 }
 
+/**
+ * Whether the provided report is an invoice room chat.
+ */
+function isInvoiceRoom(report: OnyxEntry<Report>): boolean {
+    return getChatType(report) === CONST.REPORT.CHAT_TYPE.INVOICE;
+}
+
 /**
  * Whether the provided report belongs to a Control policy and is an expense chat
  */
@@ -906,20 +922,6 @@ function isPaidGroupPolicyExpenseReport(report: OnyxEntry<Report>): boolean {
     return isExpenseReport(report) && isPaidGroupPolicy(report);
 }
 
-/**
- * Check if Report is an invoice room
- */
-function isInvoiceRoom(report: OnyxEntry<Report>): boolean {
-    return getChatType(report) === CONST.REPORT.CHAT_TYPE.INVOICE;
-}
-
-/**
- * Check if Report is an invoice report
- */
-function isInvoiceReport(report: OnyxEntry<Report> | EmptyObject): boolean {
-    return report?.type === CONST.REPORT.TYPE.INVOICE;
-}
-
 /**
  * Checks if the supplied report is an invoice report in Open state and status.
  */
@@ -2218,7 +2220,7 @@ function hasNonReimbursableTransactions(iouReportID: string | undefined): boolea
 function getMoneyRequestSpendBreakdown(report: OnyxEntry<Report>, allReportsDict: OnyxCollection<Report> = null): SpendBreakdown {
     const allAvailableReports = allReportsDict ?? allReports;
     let moneyRequestReport;
-    if (isMoneyRequestReport(report)) {
+    if (isMoneyRequestReport(report) || isInvoiceReport(report)) {
         moneyRequestReport = report;
     }
     if (allAvailableReports && report?.iouReportID) {
diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts
index 36f124a4b826..344b7df5b2eb 100644
--- a/src/types/onyx/Report.ts
+++ b/src/types/onyx/Report.ts
@@ -28,6 +28,16 @@ type Participant = {
     role?: 'admin' | 'member';
 };
 
+type InvoiceReceiver =
+    | {
+          type: 'individual';
+          accountID: number;
+      }
+    | {
+          type: 'policy';
+          policyID: string;
+      };
+
 type Participants = Record<number, Participant>;
 
 type Report = OnyxCommon.OnyxValueWithOfflineFeedback<
@@ -128,6 +138,9 @@ type Report = OnyxCommon.OnyxValueWithOfflineFeedback<
         /** Report cached total */
         cachedTotal?: string;
 
+        /** Invoice room receiver data */
+        invoiceReceiver?: InvoiceReceiver;
+
         lastMessageTranslationKey?: string;
         parentReportID?: string;
         parentReportActionID?: string;
@@ -186,16 +199,6 @@ type Report = OnyxCommon.OnyxValueWithOfflineFeedback<
         transactionThreadReportID?: string;
 
         fieldList?: Record<string, PolicyReportField>;
-
-        invoiceReceiver?:
-            | {
-                  type: typeof CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
-                  accountID: number;
-              }
-            | {
-                  type: typeof CONST.INVOICE_RECEIVER_TYPE.POLICY;
-                  policyID: string;
-              };
     },
     PolicyReportField['fieldID']
 >;

From 1b92e52f10d874af91ab346590e315aa640be244 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 17 Apr 2024 12:18:30 +0200
Subject: [PATCH 41/58] update invoice receiver const

---
 src/CONST.ts            |  9 ++++-----
 src/libs/ReportUtils.ts | 10 +++++-----
 src/libs/actions/IOU.ts |  2 +-
 3 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/src/CONST.ts b/src/CONST.ts
index 95056970457b..6467769263dd 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -839,6 +839,10 @@ const CONST = {
         OWNER_EMAIL_FAKE: '__FAKE__',
         OWNER_ACCOUNT_ID_FAKE: 0,
         DEFAULT_REPORT_NAME: 'Chat Report',
+        INVOICE_RECEIVER_TYPE: {
+            INDIVIDUAL: 'individual',
+            BUSINESS: 'policy',
+        },
     },
     NEXT_STEP: {
         FINISHED: 'Finished!',
@@ -4353,11 +4357,6 @@ const CONST = {
 
     MAX_TAX_RATE_INTEGER_PLACES: 4,
     MAX_TAX_RATE_DECIMAL_PLACES: 4,
-
-    INVOICE_RECEIVER_TYPE: {
-        INDIVIDUAL: 'individual',
-        POLICY: 'policy',
-    },
 } as const;
 
 type Country = keyof typeof CONST.ALL_COUNTRIES;
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 76693877b462..b2a1fd53afeb 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -1971,7 +1971,7 @@ function getIcons(
         const invoiceRoomReport = getReport(report.chatReportID);
         const icons = [getWorkspaceIcon(invoiceRoomReport, policy)];
 
-        if (invoiceRoomReport?.invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL) {
+        if (invoiceRoomReport?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL) {
             icons.push(...getIconsForParticipants([invoiceRoomReport?.invoiceReceiver.accountID], personalDetails));
 
             return icons;
@@ -2979,7 +2979,7 @@ function getAdminRoomInvitedParticipants(parentReportAction: ReportAction | Reco
  */
 function getInvoicePayerName(report: OnyxEntry<Report>): string {
     const invoiceReceiver = report?.invoiceReceiver;
-    const isIndividual = invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
+    const isIndividual = invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
 
     if (isIndividual) {
         return PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[invoiceReceiver.accountID]);
@@ -3009,7 +3009,7 @@ function getReportActionMessage(reportAction: ReportAction | EmptyObject, parent
  */
 function getInvoicesChatName(report: OnyxEntry<Report>): string {
     const invoiceReceiver = report?.invoiceReceiver;
-    const isIndividual = invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
+    const isIndividual = invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
     const invoiceReceiverAccountID = isIndividual ? invoiceReceiver.accountID : -1;
     const invoiceReceiverPolicyID = isIndividual ? '' : invoiceReceiver?.policyID ?? '';
     const isCurrentUserReceiver =
@@ -3032,7 +3032,7 @@ function getInvoicesChatName(report: OnyxEntry<Report>): string {
  */
 function getInvoicesChatSubtitle(report: OnyxEntry<Report>): string {
     const invoiceReceiver = report?.invoiceReceiver;
-    const isIndividual = invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
+    const isIndividual = invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
     const invoiceReceiverAccountID = isIndividual ? invoiceReceiver.accountID : -1;
     const policyID = isIndividual ? '' : invoiceReceiver?.policyID ?? '';
     let isReceiver = false;
@@ -5236,7 +5236,7 @@ function canLeaveRoom(report: OnyxEntry<Report>, isPolicyEmployee: boolean): boo
         }
 
         const isReceiverPolicyAdmin =
-            report?.invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.POLICY ? getPolicy(report?.invoiceReceiver?.policyID)?.role === CONST.POLICY.ROLE.ADMIN : false;
+            report?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS ? getPolicy(report?.invoiceReceiver?.policyID)?.role === CONST.POLICY.ROLE.ADMIN : false;
 
         if (isReceiverPolicyAdmin) {
             return false;
diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts
index 947a800f5ee5..ae93ec7413ac 100644
--- a/src/libs/actions/IOU.ts
+++ b/src/libs/actions/IOU.ts
@@ -5328,7 +5328,7 @@ function canIOUBePaid(iouReport: OnyxEntry<OnyxTypes.Report> | EmptyObject, chat
     }
 
     if (ReportUtils.isInvoiceReport(iouReport)) {
-        if (chatReport?.invoiceReceiver?.type === CONST.INVOICE_RECEIVER_TYPE.INDIVIDUAL) {
+        if (chatReport?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL) {
             return chatReport?.invoiceReceiver?.accountID === userAccountID;
         }
 

From fb69172a697a9892cc07f7a6a80581f3f3ee99e6 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 17 Apr 2024 12:22:27 +0200
Subject: [PATCH 42/58] improve getInvoicesChatSubtitle

---
 src/libs/ReportUtils.ts | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index b2a1fd53afeb..efd51ef4af99 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -3034,18 +3034,11 @@ function getInvoicesChatSubtitle(report: OnyxEntry<Report>): string {
     const invoiceReceiver = report?.invoiceReceiver;
     const isIndividual = invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
     const invoiceReceiverAccountID = isIndividual ? invoiceReceiver.accountID : -1;
-    const policyID = isIndividual ? '' : invoiceReceiver?.policyID ?? '';
-    let isReceiver = false;
-
-    if (isIndividual && invoiceReceiverAccountID === currentUserAccountID) {
-        isReceiver = true;
-    }
-
-    if (!isIndividual && PolicyUtils.isPolicyEmployee(policyID, allPolicies)) {
-        isReceiver = true;
-    }
+    const invoiceReceiverPolicyID = isIndividual ? '' : invoiceReceiver?.policyID ?? '';
+    const isCurrentUserReceiver =
+        (isIndividual && invoiceReceiverAccountID === currentUserAccountID) || (!isIndividual && PolicyUtils.isPolicyEmployee(invoiceReceiverPolicyID, allPolicies));
 
-    if (isReceiver) {
+    if (isCurrentUserReceiver) {
         let receiver = '';
 
         if (isIndividual) {
@@ -3057,7 +3050,8 @@ function getInvoicesChatSubtitle(report: OnyxEntry<Report>): string {
         return Localize.translateLocal('workspace.invoices.invoicesTo', {receiver});
     }
 
-    return Localize.translateLocal('workspace.invoices.invoicesFrom', {sender: getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`])});
+    // TODO: Check this flow in a scope of the Invoice V0.3
+    return Localize.translateLocal('workspace.invoices.invoicesFrom', {sender: getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID ?? ''}`])});
 }
 
 /**

From 2610f14920e41ec6a9b067bab9c9c4dab4c7fa77 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 17 Apr 2024 12:25:59 +0200
Subject: [PATCH 43/58] revert extra changes

---
 src/libs/ReportUtils.ts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index efd51ef4af99..f41b310c2f2e 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -141,7 +141,6 @@ type OptimisticAddCommentReportAction = Pick<
     | 'childStatusNum'
     | 'childStateNum'
     | 'errors'
-    | 'whisperedToAccountIDs'
 > & {isOptimisticAction: boolean};
 
 type OptimisticReportAction = {
@@ -192,6 +191,8 @@ type OptimisticIOUReportAction = Pick<
     | 'receipt'
     | 'whisperedToAccountIDs'
     | 'childReportID'
+    | 'childVisibleActionCount'
+    | 'childCommenterCount'
 >;
 
 type ReportRouteParams = {

From b8d94a7681ffe4d84aa94aa24ca0893d910b449f Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 17 Apr 2024 12:32:51 +0200
Subject: [PATCH 44/58] simplify invoice room subtitle

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

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index f41b310c2f2e..417cfdc09bf9 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -3149,7 +3149,7 @@ function getReportName(report: OnyxEntry<Report>, policy: OnyxEntry<Policy> = nu
  */
 function getChatRoomSubtitle(report: OnyxEntry<Report>): string | undefined {
     if (isInvoiceRoom(report)) {
-        return getInvoicesChatSubtitle(report);
+        return Localize.translateLocal('workspace.common.invoices');
     }
     if (isChatThread(report)) {
         return '';

From 04ee7b1fb55945358135fcb907271a11a34be45e Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Wed, 17 Apr 2024 12:33:55 +0200
Subject: [PATCH 45/58] Revert "integrate report subtitle for invoice room"

This reverts commit a524346f9402a98b9b6900a167c9ca15a1569078.
---
 src/languages/en.ts     |  4 ----
 src/languages/es.ts     |  4 ----
 src/languages/types.ts  |  6 ------
 src/libs/ReportUtils.ts | 31 +++----------------------------
 4 files changed, 3 insertions(+), 42 deletions(-)

diff --git a/src/languages/en.ts b/src/languages/en.ts
index f9c845b42a5a..d2f76ee4ed44 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -30,8 +30,6 @@ import type {
     GoBackMessageParams,
     GoToRoomParams,
     InstantSummaryParams,
-    InvoicesFromParams,
-    InvoicesToParams,
     LocalTimeParams,
     LoggedInAsParams,
     LogSizeParams,
@@ -2148,8 +2146,6 @@ export default {
             unlockVBACopy: "You're all set to accept payments by ACH or credit card!",
             viewUnpaidInvoices: 'View unpaid invoices',
             sendInvoice: 'Send invoice',
-            invoicesFrom: ({sender}: InvoicesFromParams) => `Invoices from ${sender}`,
-            invoicesTo: ({receiver}: InvoicesToParams) => `Invoices to ${receiver}`,
         },
         travel: {
             unlockConciergeBookingTravel: 'Unlock Concierge travel booking',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 568e14e6b241..141e3ad3db91 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -29,8 +29,6 @@ import type {
     GoBackMessageParams,
     GoToRoomParams,
     InstantSummaryParams,
-    InvoicesFromParams,
-    InvoicesToParams,
     LocalTimeParams,
     LoggedInAsParams,
     LogSizeParams,
@@ -2176,8 +2174,6 @@ export default {
             unlockVBACopy: '¡Todo listo para recibir pagos por transferencia o con tarjeta!',
             viewUnpaidInvoices: 'Ver facturas emitidas pendientes',
             sendInvoice: 'Enviar factura',
-            invoicesFrom: ({sender}: InvoicesFromParams) => `Facturas de ${sender}`,
-            invoicesTo: ({receiver}: InvoicesToParams) => `Facturas a ${receiver}`,
         },
         travel: {
             unlockConciergeBookingTravel: 'Desbloquea la reserva de viajes con Concierge',
diff --git a/src/languages/types.ts b/src/languages/types.ts
index 8c4d287b7dfc..59e1bfe40af2 100644
--- a/src/languages/types.ts
+++ b/src/languages/types.ts
@@ -251,10 +251,6 @@ type ViolationsTaxOutOfPolicyParams = {taxName?: string};
 
 type TaskCreatedActionParams = {title: string};
 
-type InvoicesFromParams = {sender: string};
-
-type InvoicesToParams = {receiver: string};
-
 /* Translation Object types */
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 type TranslationBaseValue = string | string[] | ((...args: any[]) => string);
@@ -407,6 +403,4 @@ export type {
     ZipCodeExampleFormatParams,
     LogSizeParams,
     HeldRequestParams,
-    InvoicesFromParams,
-    InvoicesToParams,
 };
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 417cfdc09bf9..0ba38d8f91de 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -3028,33 +3028,6 @@ function getInvoicesChatName(report: OnyxEntry<Report>): string {
     return getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${invoiceReceiverPolicyID}`]);
 }
 
-/**
- * Get the subtitle for an invoice room.
- */
-function getInvoicesChatSubtitle(report: OnyxEntry<Report>): string {
-    const invoiceReceiver = report?.invoiceReceiver;
-    const isIndividual = invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
-    const invoiceReceiverAccountID = isIndividual ? invoiceReceiver.accountID : -1;
-    const invoiceReceiverPolicyID = isIndividual ? '' : invoiceReceiver?.policyID ?? '';
-    const isCurrentUserReceiver =
-        (isIndividual && invoiceReceiverAccountID === currentUserAccountID) || (!isIndividual && PolicyUtils.isPolicyEmployee(invoiceReceiverPolicyID, allPolicies));
-
-    if (isCurrentUserReceiver) {
-        let receiver = '';
-
-        if (isIndividual) {
-            receiver = PersonalDetailsUtils.getDisplayNameOrDefault(allPersonalDetails?.[invoiceReceiverAccountID]);
-        } else {
-            receiver = getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${invoiceReceiver?.policyID}`]);
-        }
-
-        return Localize.translateLocal('workspace.invoices.invoicesTo', {receiver});
-    }
-
-    // TODO: Check this flow in a scope of the Invoice V0.3
-    return Localize.translateLocal('workspace.invoices.invoicesFrom', {sender: getPolicyName(report, false, allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID ?? ''}`])});
-}
-
 /**
  * Get the title for a report.
  */
@@ -3167,6 +3140,9 @@ function getChatRoomSubtitle(report: OnyxEntry<Report>): string | undefined {
     if (isArchivedRoom(report)) {
         return report?.oldPolicyName ?? '';
     }
+    if (isInvoiceRoom(report)) {
+        return Localize.translateLocal('workspace.common.invoices');
+    }
     return getPolicyName(report);
 }
 
@@ -6208,7 +6184,6 @@ export {
     getDisplayNamesWithTooltips,
     getInvoicePayerName,
     getInvoicesChatName,
-    getInvoicesChatSubtitle,
     getReportName,
     getReport,
     getReportNotificationPreference,

From 3e448b6425e8a7de5f0d3bcfaeeaffcdc438b21b Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Mon, 22 Apr 2024 14:41:29 +0200
Subject: [PATCH 46/58] use proper type

---
 src/types/onyx/Report.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts
index 05aa6bc153b9..ead526bba987 100644
--- a/src/types/onyx/Report.ts
+++ b/src/types/onyx/Report.ts
@@ -30,11 +30,11 @@ type Participant = {
 
 type InvoiceReceiver =
     | {
-          type: 'individual';
+          type: typeof CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL;
           accountID: number;
       }
     | {
-          type: 'policy';
+          type: typeof CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS;
           policyID: string;
       };
 

From de7af7f7a6b870c23a571129b4d9142fbf5dfc51 Mon Sep 17 00:00:00 2001
From: Qichen Zhu <57348009+QichenZhu@users.noreply.github.com>
Date: Tue, 23 Apr 2024 11:03:44 +1200
Subject: [PATCH 47/58] fix adding a reaction on a highlighted message moves up
 and down strangely

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

diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts
index e9efc84e8807..52e4f10178f9 100644
--- a/src/styles/utils/index.ts
+++ b/src/styles/utils/index.ts
@@ -1452,6 +1452,7 @@ const createStyleUtils = (theme: ThemeColors, styles: ThemeStyles) => ({
             ...positioning.r4,
             ...styles.cursorDefault,
             ...styles.userSelectNone,
+            overflowAnchor: 'none',
             position: 'absolute',
             zIndex: 8,
         }),

From 4b5db30ee86f443b66da0a9151ac7a661046d9e5 Mon Sep 17 00:00:00 2001
From: Artem Makushov <waterim3009@gmail.com>
Date: Wed, 24 Apr 2024 16:52:22 +0200
Subject: [PATCH 48/58] fix translations, CONST

---
 src/CONST.ts            | 1 -
 src/languages/en.ts     | 1 +
 src/languages/es.ts     | 1 +
 src/libs/actions/IOU.ts | 2 +-
 4 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/CONST.ts b/src/CONST.ts
index c477cb735c0f..78ef4e1873c4 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -1454,7 +1454,6 @@ const CONST = {
             PAY: 'pay',
             SPLIT: 'split',
             REQUEST: 'request',
-            TRACK_EXPENSE: 'track-expense',
             INVOICE: 'invoice',
             SUBMIT: 'submit',
             TRACK: 'track',
diff --git a/src/languages/en.ts b/src/languages/en.ts
index 824e1eca5722..b1c3a45e9db7 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -518,6 +518,7 @@ export default {
             split: 'split an expense',
             submit: 'submit an expense',
             track: 'track an expense',
+            invoice: 'invoice an expense',
         },
     },
     reportAction: {
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 529084aa2061..53c631036ab5 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -511,6 +511,7 @@ export default {
             split: 'dividir un gasto',
             submit: 'presentar un gasto',
             track: 'rastrear un gasto',
+            invoice: 'facturar un gasto',
         },
     },
     reportAction: {
diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts
index 2e5a63330455..45bcf7c2fad1 100644
--- a/src/libs/actions/IOU.ts
+++ b/src/libs/actions/IOU.ts
@@ -5337,7 +5337,7 @@ function canIOUBePaid(iouReport: OnyxEntry<OnyxTypes.Report> | EmptyObject, chat
             return chatReport?.invoiceReceiver?.accountID === userAccountID;
         }
 
-        return getPolicy(chatReport?.invoiceReceiver?.policyID).role === CONST.POLICY.ROLE.ADMIN;
+        return PolicyUtils.getPolicy(chatReport?.invoiceReceiver?.policyID).role === CONST.POLICY.ROLE.ADMIN;
     }
 
     const isPayer = ReportUtils.isPayer(

From 7d05ac2e4c4ed420af245f443da22b6839c51627 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Thu, 25 Apr 2024 14:31:14 +0200
Subject: [PATCH 49/58] remove payment waiting banner

---
 src/components/MoneyReportHeader.tsx          | 14 ++-------
 src/components/PaymentWaitingBanner/index.tsx | 31 -------------------
 .../ReportActionItem/ReportPreview.tsx        |  6 ----
 src/languages/en.ts                           |  2 --
 src/languages/es.ts                           |  2 --
 src/languages/types.ts                        |  3 --
 src/libs/ReportUtils.ts                       |  8 -----
 7 files changed, 2 insertions(+), 64 deletions(-)
 delete mode 100644 src/components/PaymentWaitingBanner/index.tsx

diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx
index 0f5d74f71d31..56dc6bf0075d 100644
--- a/src/components/MoneyReportHeader.tsx
+++ b/src/components/MoneyReportHeader.tsx
@@ -22,7 +22,6 @@ import ConfirmModal from './ConfirmModal';
 import HeaderWithBackButton from './HeaderWithBackButton';
 import * as Expensicons from './Icon/Expensicons';
 import MoneyReportHeaderStatusBar from './MoneyReportHeaderStatusBar';
-import PaymentWaitingBanner from './PaymentWaitingBanner';
 import ProcessMoneyReportHoldMenu from './ProcessMoneyReportHoldMenu';
 import SettlementButton from './SettlementButton';
 
@@ -100,10 +99,6 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money
 
     const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton;
 
-    const shouldShowWaitingNote = ReportUtils.isInvoiceAwaitingPayment(moneyRequestReport);
-
-    const invoicePayerName = ReportUtils.getInvoicePayerName(chatReport);
-
     const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0;
     const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport);
     const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE;
@@ -113,7 +108,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money
     const formattedAmount = CurrencyUtils.convertToDisplayString(reimbursableSpend, moneyRequestReport.currency);
     const [nonHeldAmount, fullAmount] = ReportUtils.getNonHeldAndFullAmount(moneyRequestReport, policy);
     const displayedAmount = ReportUtils.hasHeldExpenses(moneyRequestReport.reportID) && canAllowSettlement ? nonHeldAmount : formattedAmount;
-    const isMoreContentShown = shouldShowNextStep || (shouldShowAnyButton && isSmallScreenWidth) || shouldShowWaitingNote;
+    const isMoreContentShown = shouldShowNextStep || (shouldShowAnyButton && isSmallScreenWidth);
 
     const confirmPayment = (type?: PaymentMethodType | undefined) => {
         if (!type) {
@@ -193,7 +188,7 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money
                 shouldShowBackButton={isSmallScreenWidth}
                 onBackButtonPress={() => Navigation.goBack(undefined, false, true)}
                 // Shows border if no buttons or next steps are showing below the header
-                shouldShowBorderBottom={!(shouldShowAnyButton && isSmallScreenWidth) && !(shouldShowNextStep && !isSmallScreenWidth) && !shouldShowWaitingNote}
+                shouldShowBorderBottom={!(shouldShowAnyButton && isSmallScreenWidth) && !(shouldShowNextStep && !isSmallScreenWidth)}
                 shouldShowThreeDotsButton
                 threeDotsMenuItems={threeDotsMenuItems}
                 threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(windowWidth)}
@@ -268,11 +263,6 @@ function MoneyReportHeader({session, policy, chatReport, nextStep, report: money
                         <MoneyReportHeaderStatusBar nextStep={nextStep} />
                     </View>
                 )}
-                {shouldShowWaitingNote && (
-                    <View style={[styles.ph5, styles.pb3]}>
-                        <PaymentWaitingBanner payerName={invoicePayerName} />
-                    </View>
-                )}
             </View>
             {isHoldMenuVisible && requestType !== undefined && (
                 <ProcessMoneyReportHoldMenu
diff --git a/src/components/PaymentWaitingBanner/index.tsx b/src/components/PaymentWaitingBanner/index.tsx
deleted file mode 100644
index af13711f08e0..000000000000
--- a/src/components/PaymentWaitingBanner/index.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-import {View} from 'react-native';
-import Icon from '@components/Icon';
-import * as Expensicons from '@components/Icon/Expensicons';
-import Text from '@components/Text';
-import useLocalize from '@hooks/useLocalize';
-import useTheme from '@hooks/useTheme';
-import useThemeStyles from '@hooks/useThemeStyles';
-
-type PaymentWaitingBannerProps = {
-    payerName: string;
-};
-
-function PaymentWaitingBanner({payerName}: PaymentWaitingBannerProps) {
-    const theme = useTheme();
-    const styles = useThemeStyles();
-    const {translate} = useLocalize();
-
-    return (
-        <View style={[styles.flexRow, styles.alignItemsCenter]}>
-            <Icon
-                src={Expensicons.Hourglass}
-                fill={theme.icon}
-            />
-
-            <Text style={[styles.inlineSystemMessage, styles.flexShrink1]}>{translate('iou.awaitingPayment', {payerName})}</Text>
-        </View>
-    );
-}
-
-export default PaymentWaitingBanner;
diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx
index 4cba437b0d80..5c78e1e2604e 100644
--- a/src/components/ReportActionItem/ReportPreview.tsx
+++ b/src/components/ReportActionItem/ReportPreview.tsx
@@ -8,7 +8,6 @@ import Button from '@components/Button';
 import Icon from '@components/Icon';
 import * as Expensicons from '@components/Icon/Expensicons';
 import OfflineWithFeedback from '@components/OfflineWithFeedback';
-import PaymentWaitingBanner from '@components/PaymentWaitingBanner';
 import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
 import RenderHTML from '@components/RenderHTML';
 import SettlementButton from '@components/SettlementButton';
@@ -216,10 +215,6 @@ function ReportPreview({
     const shouldPromptUserToAddBankAccount = ReportUtils.hasMissingPaymentMethod(userWallet, iouReportID);
     const shouldShowRBR = !iouSettled && hasErrors;
 
-    const shouldShowWaitingNote = ReportUtils.isInvoiceAwaitingPayment(iouReport);
-
-    const invoicePayerName = ReportUtils.getInvoicePayerName(chatReport);
-
     /*
      Show subtitle if at least one of the expenses is not being smart scanned, and either:
      - There is more than one expense – in this case, the "X expenses, Y scanning" subtitle is shown;
@@ -357,7 +352,6 @@ function ReportPreview({
                                         isDisabled={shouldDisableSubmitButton}
                                     />
                                 )}
-                                {shouldShowWaitingNote && <PaymentWaitingBanner payerName={invoicePayerName} />}
                             </View>
                         </View>
                     </View>
diff --git a/src/languages/en.ts b/src/languages/en.ts
index d9c6e7f0d5b3..2c3d58c171fe 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -9,7 +9,6 @@ import type {
     AlreadySignedInParams,
     AmountEachParams,
     ApprovedAmountParams,
-    AwaitingPaymentParams,
     BeginningOfChatHistoryAdminRoomPartOneParams,
     BeginningOfChatHistoryAnnounceRoomPartOneParams,
     BeginningOfChatHistoryAnnounceRoomPartTwo,
@@ -740,7 +739,6 @@ export default {
         set: 'set',
         changed: 'changed',
         removed: 'removed',
-        awaitingPayment: ({payerName}: AwaitingPaymentParams) => `Awaiting payment by ${payerName}`,
         chooseARate: ({unit}: ReimbursementRateParams) => `Select a workspace reimbursement rate per ${unit}`,
     },
     notificationPreferencesPage: {
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 91462121f52c..e56fd67db883 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -7,7 +7,6 @@ import type {
     AlreadySignedInParams,
     AmountEachParams,
     ApprovedAmountParams,
-    AwaitingPaymentParams,
     BeginningOfChatHistoryAdminRoomPartOneParams,
     BeginningOfChatHistoryAnnounceRoomPartOneParams,
     BeginningOfChatHistoryAnnounceRoomPartTwo,
@@ -735,7 +734,6 @@ export default {
         set: 'estableció',
         changed: 'cambió',
         removed: 'eliminó',
-        awaitingPayment: ({payerName}: AwaitingPaymentParams) => `A la espera de pago por ${payerName}`,
         chooseARate: ({unit}: ReimbursementRateParams) => `Seleccione una tasa de reembolso del espacio de trabajo por ${unit}`,
     },
     notificationPreferencesPage: {
diff --git a/src/languages/types.ts b/src/languages/types.ts
index c81720f1773b..9426e343bbf0 100644
--- a/src/languages/types.ts
+++ b/src/languages/types.ts
@@ -136,8 +136,6 @@ type PayerSettledParams = {amount: number | string};
 
 type WaitingOnBankAccountParams = {submitterDisplayName: string};
 
-type AwaitingPaymentParams = {payerName: string};
-
 type CanceledRequestParams = {amount: string; submitterDisplayName: string};
 
 type AdminCanceledRequestParams = {manager: string; amount: string};
@@ -398,7 +396,6 @@ export type {
     ViolationsTagOutOfPolicyParams,
     ViolationsTaxOutOfPolicyParams,
     WaitingOnBankAccountParams,
-    AwaitingPaymentParams,
     WalletProgramParams,
     UsePlusButtonParams,
     WeSentYouMagicSignInLinkParams,
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 12df7ba20a52..781cf13d23f6 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -6286,13 +6286,6 @@ function canReportBeMentionedWithinPolicy(report: OnyxEntry<Report>, policyID: s
     return isChatRoom(report) && !isThread(report);
 }
 
-/**
- * Check if a invoice report is awaiting for payment
- */
-function isInvoiceAwaitingPayment(report: OnyxEntry<Report>): boolean {
-    return !isSettled(report?.reportID ?? '') && isInvoiceReport(report);
-}
-
 export {
     addDomainToShortMention,
     areAllRequestsBeingSmartScanned,
@@ -6519,7 +6512,6 @@ export {
     isInvoiceRoom,
     isInvoiceReport,
     isOpenInvoiceReport,
-    isInvoiceAwaitingPayment,
     navigateToDetailsPage,
     navigateToPrivateNotes,
     parseReportRouteParams,

From 4264b50f4c90d38f42cae81ab6d1b12c5254d333 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Thu, 25 Apr 2024 14:36:44 +0200
Subject: [PATCH 50/58] show invoice room in sidebar

---
 src/libs/ReportUtils.ts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 781cf13d23f6..7589c7963a0f 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -4896,7 +4896,8 @@ function shouldReportBeInOptionList({
             !isMoneyRequestReport(report) &&
             !isTaskReport(report) &&
             !isSelfDM(report) &&
-            !isGroupChat(report))
+            !isGroupChat(report) &&
+            !isInvoiceRoom(report))
     ) {
         return false;
     }

From 7ff74bea5e068a5461ce95c2bfc3a6e924dc0fc6 Mon Sep 17 00:00:00 2001
From: Rocio Perez-Cano <rocio@expensify.com>
Date: Thu, 25 Apr 2024 16:06:07 +0200
Subject: [PATCH 51/58] Update webpack-dev-server to fix vulnerabilities

---
 package-lock.json | 448 ++++++++++++++++++++++++++++++++++++----------
 package.json      |   2 +-
 2 files changed, 359 insertions(+), 91 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 893b171ecc55..2f4b82b56341 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -242,7 +242,7 @@
         "webpack": "^5.76.0",
         "webpack-bundle-analyzer": "^4.5.0",
         "webpack-cli": "^4.10.0",
-        "webpack-dev-server": "^4.9.3",
+        "webpack-dev-server": "^5.0.4",
         "webpack-merge": "^5.8.0",
         "yaml": "^2.2.1"
       },
@@ -7092,9 +7092,10 @@
       "license": "MIT"
     },
     "node_modules/@leichtgewicht/ip-codec": {
-      "version": "2.0.4",
-      "dev": true,
-      "license": "MIT"
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz",
+      "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==",
+      "dev": true
     },
     "node_modules/@lwc/eslint-plugin-lwc": {
       "version": "1.7.2",
@@ -12174,9 +12175,10 @@
       }
     },
     "node_modules/@types/bonjour": {
-      "version": "3.5.10",
+      "version": "3.5.13",
+      "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz",
+      "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "@types/node": "*"
       }
@@ -12213,9 +12215,10 @@
       }
     },
     "node_modules/@types/connect-history-api-fallback": {
-      "version": "1.3.5",
+      "version": "1.5.4",
+      "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz",
+      "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "@types/express-serve-static-core": "*",
         "@types/node": "*"
@@ -12283,22 +12286,25 @@
       "license": "MIT"
     },
     "node_modules/@types/express": {
-      "version": "4.17.13",
-      "license": "MIT",
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
+      "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
       "dependencies": {
         "@types/body-parser": "*",
-        "@types/express-serve-static-core": "^4.17.18",
+        "@types/express-serve-static-core": "^4.17.33",
         "@types/qs": "*",
         "@types/serve-static": "*"
       }
     },
     "node_modules/@types/express-serve-static-core": {
-      "version": "4.17.30",
-      "license": "MIT",
+      "version": "4.19.0",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz",
+      "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==",
       "dependencies": {
         "@types/node": "*",
         "@types/qs": "*",
-        "@types/range-parser": "*"
+        "@types/range-parser": "*",
+        "@types/send": "*"
       }
     },
     "node_modules/@types/fs-extra": {
@@ -12358,6 +12364,11 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/@types/http-errors": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
+      "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA=="
+    },
     "node_modules/@types/http-proxy": {
       "version": "1.17.9",
       "dev": true,
@@ -12469,8 +12480,9 @@
       "integrity": "sha512-H9VZ9YqE+H28FQVchC83RCs5xQ2J7mAAv6qdDEaWmXEVl3OpdH+xfrSUzQ1lp7U7oSTRZ0RvW08ASPJsYBi7Cw=="
     },
     "node_modules/@types/mime": {
-      "version": "3.0.1",
-      "license": "MIT"
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
+      "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="
     },
     "node_modules/@types/minimatch": {
       "version": "3.0.5",
@@ -12489,6 +12501,15 @@
         "undici-types": "~5.26.4"
       }
     },
+    "node_modules/@types/node-forge": {
+      "version": "1.3.11",
+      "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz",
+      "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/normalize-package-data": {
       "version": "2.4.4",
       "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
@@ -12615,9 +12636,10 @@
       }
     },
     "node_modules/@types/retry": {
-      "version": "0.12.0",
-      "dev": true,
-      "license": "MIT"
+      "version": "0.12.2",
+      "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz",
+      "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==",
+      "dev": true
     },
     "node_modules/@types/scheduler": {
       "version": "0.16.2",
@@ -12627,20 +12649,32 @@
       "version": "7.5.4",
       "license": "MIT"
     },
+    "node_modules/@types/send": {
+      "version": "0.17.4",
+      "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
+      "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
+      "dependencies": {
+        "@types/mime": "^1",
+        "@types/node": "*"
+      }
+    },
     "node_modules/@types/serve-index": {
-      "version": "1.9.1",
+      "version": "1.9.4",
+      "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz",
+      "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "@types/express": "*"
       }
     },
     "node_modules/@types/serve-static": {
-      "version": "1.15.0",
-      "license": "MIT",
+      "version": "1.15.7",
+      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz",
+      "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==",
       "dependencies": {
-        "@types/mime": "*",
-        "@types/node": "*"
+        "@types/http-errors": "*",
+        "@types/node": "*",
+        "@types/send": "*"
       }
     },
     "node_modules/@types/setimmediate": {
@@ -12649,9 +12683,10 @@
       "license": "MIT"
     },
     "node_modules/@types/sockjs": {
-      "version": "0.3.33",
+      "version": "0.3.36",
+      "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz",
+      "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "@types/node": "*"
       }
@@ -12705,9 +12740,10 @@
       }
     },
     "node_modules/@types/ws": {
-      "version": "8.5.3",
+      "version": "8.5.10",
+      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz",
+      "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "@types/node": "*"
       }
@@ -15531,21 +15567,15 @@
       "license": "MIT"
     },
     "node_modules/bonjour-service": {
-      "version": "1.0.13",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz",
+      "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
-        "array-flatten": "^2.1.2",
-        "dns-equal": "^1.0.0",
         "fast-deep-equal": "^3.1.3",
         "multicast-dns": "^7.2.5"
       }
     },
-    "node_modules/bonjour-service/node_modules/array-flatten": {
-      "version": "2.1.2",
-      "dev": true,
-      "license": "MIT"
-    },
     "node_modules/boolbase": {
       "version": "1.0.0",
       "license": "ISC"
@@ -15961,6 +15991,21 @@
       "version": "1.0.3",
       "license": "MIT"
     },
+    "node_modules/bundle-name": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+      "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
+      "dev": true,
+      "dependencies": {
+        "run-applescript": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/bytes": {
       "version": "3.0.0",
       "license": "MIT",
@@ -17874,6 +17919,22 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/default-browser": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz",
+      "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==",
+      "dev": true,
+      "dependencies": {
+        "bundle-name": "^4.1.0",
+        "default-browser-id": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/default-browser-id": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz",
@@ -17889,6 +17950,18 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/default-browser/node_modules/default-browser-id": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz",
+      "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==",
+      "dev": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/default-gateway": {
       "version": "6.0.3",
       "dev": true,
@@ -18305,15 +18378,11 @@
       "license": "MIT",
       "optional": true
     },
-    "node_modules/dns-equal": {
-      "version": "1.0.0",
-      "dev": true,
-      "license": "MIT"
-    },
     "node_modules/dns-packet": {
-      "version": "5.4.0",
+      "version": "5.6.1",
+      "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz",
+      "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "@leichtgewicht/ip-codec": "^2.0.1"
       },
@@ -23384,6 +23453,39 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/is-inside-container": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+      "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+      "dev": true,
+      "dependencies": {
+        "is-docker": "^3.0.0"
+      },
+      "bin": {
+        "is-inside-container": "cli.js"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-inside-container/node_modules/is-docker": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+      "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+      "dev": true,
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/is-interactive": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
@@ -23453,6 +23555,18 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-network-error": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz",
+      "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==",
+      "dev": true,
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/is-number": {
       "version": "7.0.0",
       "license": "MIT",
@@ -26748,6 +26862,16 @@
         "language-subtag-registry": "~0.3.2"
       }
     },
+    "node_modules/launch-editor": {
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz",
+      "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==",
+      "dev": true,
+      "dependencies": {
+        "picocolors": "^1.0.0",
+        "shell-quote": "^1.8.1"
+      }
+    },
     "node_modules/lazy-cache": {
       "version": "1.0.4",
       "license": "MIT",
@@ -28401,8 +28525,9 @@
     },
     "node_modules/multicast-dns": {
       "version": "7.2.5",
+      "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz",
+      "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "dns-packet": "^5.2.2",
         "thunky": "^1.0.2"
@@ -29477,15 +29602,20 @@
       }
     },
     "node_modules/p-retry": {
-      "version": "4.6.2",
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz",
+      "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
-        "@types/retry": "0.12.0",
+        "@types/retry": "0.12.2",
+        "is-network-error": "^1.0.0",
         "retry": "^0.13.1"
       },
       "engines": {
-        "node": ">=8"
+        "node": ">=16.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
       }
     },
     "node_modules/p-try": {
@@ -33050,8 +33180,9 @@
     },
     "node_modules/retry": {
       "version": "0.13.1",
+      "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
+      "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
       "dev": true,
-      "license": "MIT",
       "engines": {
         "node": ">= 4"
       }
@@ -33116,6 +33247,18 @@
       "dev": true,
       "license": "BSD-3-Clause"
     },
+    "node_modules/run-applescript": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz",
+      "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==",
+      "dev": true,
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/run-node": {
       "version": "1.0.0",
       "dev": true,
@@ -33298,10 +33441,12 @@
       "license": "MIT"
     },
     "node_modules/selfsigned": {
-      "version": "2.0.1",
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz",
+      "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
+        "@types/node-forge": "^1.3.0",
         "node-forge": "^1"
       },
       "engines": {
@@ -35310,8 +35455,9 @@
     },
     "node_modules/thunky": {
       "version": "1.1.0",
-      "dev": true,
-      "license": "MIT"
+      "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
+      "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
+      "dev": true
     },
     "node_modules/time-analytics-webpack-plugin": {
       "version": "0.1.17",
@@ -37069,54 +37215,59 @@
       }
     },
     "node_modules/webpack-dev-server": {
-      "version": "4.10.0",
+      "version": "5.0.4",
+      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz",
+      "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
-        "@types/bonjour": "^3.5.9",
-        "@types/connect-history-api-fallback": "^1.3.5",
-        "@types/express": "^4.17.13",
-        "@types/serve-index": "^1.9.1",
-        "@types/serve-static": "^1.13.10",
-        "@types/sockjs": "^0.3.33",
-        "@types/ws": "^8.5.1",
+        "@types/bonjour": "^3.5.13",
+        "@types/connect-history-api-fallback": "^1.5.4",
+        "@types/express": "^4.17.21",
+        "@types/serve-index": "^1.9.4",
+        "@types/serve-static": "^1.15.5",
+        "@types/sockjs": "^0.3.36",
+        "@types/ws": "^8.5.10",
         "ansi-html-community": "^0.0.8",
-        "bonjour-service": "^1.0.11",
-        "chokidar": "^3.5.3",
+        "bonjour-service": "^1.2.1",
+        "chokidar": "^3.6.0",
         "colorette": "^2.0.10",
         "compression": "^1.7.4",
         "connect-history-api-fallback": "^2.0.0",
         "default-gateway": "^6.0.3",
         "express": "^4.17.3",
         "graceful-fs": "^4.2.6",
-        "html-entities": "^2.3.2",
+        "html-entities": "^2.4.0",
         "http-proxy-middleware": "^2.0.3",
-        "ipaddr.js": "^2.0.1",
-        "open": "^8.0.9",
-        "p-retry": "^4.5.0",
-        "rimraf": "^3.0.2",
-        "schema-utils": "^4.0.0",
-        "selfsigned": "^2.0.1",
+        "ipaddr.js": "^2.1.0",
+        "launch-editor": "^2.6.1",
+        "open": "^10.0.3",
+        "p-retry": "^6.2.0",
+        "rimraf": "^5.0.5",
+        "schema-utils": "^4.2.0",
+        "selfsigned": "^2.4.1",
         "serve-index": "^1.9.1",
         "sockjs": "^0.3.24",
         "spdy": "^4.0.2",
-        "webpack-dev-middleware": "^5.3.1",
-        "ws": "^8.4.2"
+        "webpack-dev-middleware": "^7.1.0",
+        "ws": "^8.16.0"
       },
       "bin": {
         "webpack-dev-server": "bin/webpack-dev-server.js"
       },
       "engines": {
-        "node": ">= 12.13.0"
+        "node": ">= 18.12.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/webpack"
       },
       "peerDependencies": {
-        "webpack": "^4.37.0 || ^5.0.0"
+        "webpack": "^5.0.0"
       },
       "peerDependenciesMeta": {
+        "webpack": {
+          "optional": true
+        },
         "webpack-cli": {
           "optional": true
         }
@@ -37124,8 +37275,9 @@
     },
     "node_modules/webpack-dev-server/node_modules/ajv-keywords": {
       "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+      "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "fast-deep-equal": "^3.1.3"
       },
@@ -37133,10 +37285,54 @@
         "ajv": "^8.8.2"
       }
     },
+    "node_modules/webpack-dev-server/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
     "node_modules/webpack-dev-server/node_modules/colorette": {
       "version": "2.0.20",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
+      "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
+      "dev": true
+    },
+    "node_modules/webpack-dev-server/node_modules/define-lazy-prop": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+      "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
       "dev": true,
-      "license": "MIT"
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/webpack-dev-server/node_modules/glob": {
+      "version": "10.3.12",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz",
+      "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==",
+      "dev": true,
+      "dependencies": {
+        "foreground-child": "^3.1.0",
+        "jackspeak": "^2.3.6",
+        "minimatch": "^9.0.1",
+        "minipass": "^7.0.4",
+        "path-scurry": "^1.10.2"
+      },
+      "bin": {
+        "glob": "dist/esm/bin.mjs"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
     },
     "node_modules/webpack-dev-server/node_modules/ipaddr.js": {
       "version": "2.1.0",
@@ -37146,21 +37342,86 @@
         "node": ">= 10"
       }
     },
-    "node_modules/webpack-dev-server/node_modules/memfs": {
-      "version": "3.5.3",
+    "node_modules/webpack-dev-server/node_modules/is-wsl": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz",
+      "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==",
       "dev": true,
-      "license": "Unlicense",
       "dependencies": {
-        "fs-monkey": "^1.0.4"
+        "is-inside-container": "^1.0.0"
       },
       "engines": {
-        "node": ">= 4.0.0"
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/webpack-dev-server/node_modules/minimatch": {
+      "version": "9.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
+      "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/webpack-dev-server/node_modules/minipass": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
+      "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/webpack-dev-server/node_modules/open": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz",
+      "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==",
+      "dev": true,
+      "dependencies": {
+        "default-browser": "^5.2.1",
+        "define-lazy-prop": "^3.0.0",
+        "is-inside-container": "^1.0.0",
+        "is-wsl": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/webpack-dev-server/node_modules/rimraf": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz",
+      "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==",
+      "dev": true,
+      "dependencies": {
+        "glob": "^10.3.7"
+      },
+      "bin": {
+        "rimraf": "dist/esm/bin.mjs"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
       }
     },
     "node_modules/webpack-dev-server/node_modules/schema-utils": {
       "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
+      "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "@types/json-schema": "^7.0.9",
         "ajv": "^8.9.0",
@@ -37176,25 +37437,32 @@
       }
     },
     "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": {
-      "version": "5.3.3",
+      "version": "7.2.1",
+      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz",
+      "integrity": "sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "colorette": "^2.0.10",
-        "memfs": "^3.4.3",
+        "memfs": "^4.6.0",
         "mime-types": "^2.1.31",
+        "on-finished": "^2.4.1",
         "range-parser": "^1.2.1",
         "schema-utils": "^4.0.0"
       },
       "engines": {
-        "node": ">= 12.13.0"
+        "node": ">= 18.12.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/webpack"
       },
       "peerDependencies": {
-        "webpack": "^4.0.0 || ^5.0.0"
+        "webpack": "^5.0.0"
+      },
+      "peerDependenciesMeta": {
+        "webpack": {
+          "optional": true
+        }
       }
     },
     "node_modules/webpack-hot-middleware": {
diff --git a/package.json b/package.json
index 6530f17f23b6..f9e8edff563d 100644
--- a/package.json
+++ b/package.json
@@ -294,7 +294,7 @@
     "webpack": "^5.76.0",
     "webpack-bundle-analyzer": "^4.5.0",
     "webpack-cli": "^4.10.0",
-    "webpack-dev-server": "^4.9.3",
+    "webpack-dev-server": "^5.0.4",
     "webpack-merge": "^5.8.0",
     "yaml": "^2.2.1"
   },

From 0752135fd427c98bb649e947365ab3df8b354e46 Mon Sep 17 00:00:00 2001
From: Rocio Perez-Cano <rocio@expensify.com>
Date: Thu, 25 Apr 2024 16:20:12 +0200
Subject: [PATCH 52/58] Use same version for both libraries

---
 package-lock.json | 85 +++++++++++++++++++++++++++--------------------
 package.json      |  2 +-
 2 files changed, 50 insertions(+), 37 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 2f4b82b56341..e59397b33c52 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -241,7 +241,7 @@
         "wait-port": "^0.2.9",
         "webpack": "^5.76.0",
         "webpack-bundle-analyzer": "^4.5.0",
-        "webpack-cli": "^4.10.0",
+        "webpack-cli": "^5.0.4",
         "webpack-dev-server": "^5.0.4",
         "webpack-merge": "^5.8.0",
         "yaml": "^2.2.1"
@@ -13585,31 +13585,42 @@
       "license": "MIT"
     },
     "node_modules/@webpack-cli/configtest": {
-      "version": "1.2.0",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz",
+      "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==",
       "dev": true,
-      "license": "MIT",
+      "engines": {
+        "node": ">=14.15.0"
+      },
       "peerDependencies": {
-        "webpack": "4.x.x || 5.x.x",
-        "webpack-cli": "4.x.x"
+        "webpack": "5.x.x",
+        "webpack-cli": "5.x.x"
       }
     },
     "node_modules/@webpack-cli/info": {
-      "version": "1.5.0",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz",
+      "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==",
       "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "envinfo": "^7.7.3"
+      "engines": {
+        "node": ">=14.15.0"
       },
       "peerDependencies": {
-        "webpack-cli": "4.x.x"
+        "webpack": "5.x.x",
+        "webpack-cli": "5.x.x"
       }
     },
     "node_modules/@webpack-cli/serve": {
-      "version": "1.7.0",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz",
+      "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==",
       "dev": true,
-      "license": "MIT",
+      "engines": {
+        "node": ">=14.15.0"
+      },
       "peerDependencies": {
-        "webpack-cli": "4.x.x"
+        "webpack": "5.x.x",
+        "webpack-cli": "5.x.x"
       },
       "peerDependenciesMeta": {
         "webpack-dev-server": {
@@ -23119,11 +23130,12 @@
       }
     },
     "node_modules/interpret": {
-      "version": "2.2.0",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz",
+      "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==",
       "dev": true,
-      "license": "MIT",
       "engines": {
-        "node": ">= 0.10"
+        "node": ">=10.13.0"
       }
     },
     "node_modules/invariant": {
@@ -32783,14 +32795,15 @@
       }
     },
     "node_modules/rechoir": {
-      "version": "0.7.1",
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
+      "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
-        "resolve": "^1.9.0"
+        "resolve": "^1.20.0"
       },
       "engines": {
-        "node": ">= 0.10"
+        "node": ">= 10.13.0"
       }
     },
     "node_modules/redent": {
@@ -37079,43 +37092,42 @@
       }
     },
     "node_modules/webpack-cli": {
-      "version": "4.10.0",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz",
+      "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
       "dev": true,
-      "license": "MIT",
       "dependencies": {
         "@discoveryjs/json-ext": "^0.5.0",
-        "@webpack-cli/configtest": "^1.2.0",
-        "@webpack-cli/info": "^1.5.0",
-        "@webpack-cli/serve": "^1.7.0",
+        "@webpack-cli/configtest": "^2.1.1",
+        "@webpack-cli/info": "^2.0.2",
+        "@webpack-cli/serve": "^2.0.5",
         "colorette": "^2.0.14",
-        "commander": "^7.0.0",
+        "commander": "^10.0.1",
         "cross-spawn": "^7.0.3",
+        "envinfo": "^7.7.3",
         "fastest-levenshtein": "^1.0.12",
         "import-local": "^3.0.2",
-        "interpret": "^2.2.0",
-        "rechoir": "^0.7.0",
+        "interpret": "^3.1.1",
+        "rechoir": "^0.8.0",
         "webpack-merge": "^5.7.3"
       },
       "bin": {
         "webpack-cli": "bin/cli.js"
       },
       "engines": {
-        "node": ">=10.13.0"
+        "node": ">=14.15.0"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/webpack"
       },
       "peerDependencies": {
-        "webpack": "4.x.x || 5.x.x"
+        "webpack": "5.x.x"
       },
       "peerDependenciesMeta": {
         "@webpack-cli/generators": {
           "optional": true
         },
-        "@webpack-cli/migrate": {
-          "optional": true
-        },
         "webpack-bundle-analyzer": {
           "optional": true
         },
@@ -37130,11 +37142,12 @@
       "license": "MIT"
     },
     "node_modules/webpack-cli/node_modules/commander": {
-      "version": "7.2.0",
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+      "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
       "dev": true,
-      "license": "MIT",
       "engines": {
-        "node": ">= 10"
+        "node": ">=14"
       }
     },
     "node_modules/webpack-dev-middleware": {
diff --git a/package.json b/package.json
index f9e8edff563d..273265da9f06 100644
--- a/package.json
+++ b/package.json
@@ -293,7 +293,7 @@
     "wait-port": "^0.2.9",
     "webpack": "^5.76.0",
     "webpack-bundle-analyzer": "^4.5.0",
-    "webpack-cli": "^4.10.0",
+    "webpack-cli": "^5.0.4",
     "webpack-dev-server": "^5.0.4",
     "webpack-merge": "^5.8.0",
     "yaml": "^2.2.1"

From 09316a413df64fc454a2ad9c3e05ed4eecd56630 Mon Sep 17 00:00:00 2001
From: Rocio Perez-Cano <rocio@expensify.com>
Date: Thu, 25 Apr 2024 16:26:26 +0200
Subject: [PATCH 53/58] Fix proxySettings types

---
 config/webpack/webpack.dev.ts | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/config/webpack/webpack.dev.ts b/config/webpack/webpack.dev.ts
index 8f32a2d95c99..4a004fb61d6d 100644
--- a/config/webpack/webpack.dev.ts
+++ b/config/webpack/webpack.dev.ts
@@ -21,16 +21,12 @@ const getConfiguration = (environment: Environment): Promise<Configuration> =>
             process.env.USE_WEB_PROXY === 'false'
                 ? {}
                 : {
-                      proxy: {
-                          // eslint-disable-next-line @typescript-eslint/naming-convention
-                          '/api': 'http://[::1]:9000',
-                          // eslint-disable-next-line @typescript-eslint/naming-convention
-                          '/staging': 'http://[::1]:9000',
-                          // eslint-disable-next-line @typescript-eslint/naming-convention
-                          '/chat-attachments': 'http://[::1]:9000',
-                          // eslint-disable-next-line @typescript-eslint/naming-convention
-                          '/receipts': 'http://[::1]:9000',
-                      },
+                      proxy: [
+                          {
+                              context: ["/api", "/staging", "/chat-attachments", "/receipts"],
+                              target: 'http://[::1]:9000',
+                          },
+                      ],
                   };
 
         const baseConfig = getCommonConfiguration(environment);

From c852145ed838a9b4b2caffef35cfeed01f2379a6 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 26 Apr 2024 10:22:49 +0200
Subject: [PATCH 54/58] clarify comments

---
 src/libs/ReportActionsUtils.ts | 2 +-
 src/libs/ReportUtils.ts        | 6 ------
 2 files changed, 1 insertion(+), 7 deletions(-)

diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index a666d81a180e..9491b6141536 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -226,7 +226,7 @@ function isTransactionThread(parentReportAction: OnyxEntry<ReportAction> | Empty
  * Returns the reportID for the transaction thread associated with a report by iterating over the reportActions and identifying the IOU report actions with a childReportID. Returns a reportID if there is exactly one transaction thread for the report, and null otherwise.
  */
 function getOneTransactionThreadReportID(reportID: string, reportActions: OnyxEntry<ReportActions> | ReportAction[], isOffline: boolean | undefined = undefined): string | null {
-    // If the report is not an IOU or Expense report, it shouldn't be treated as one-transaction report.
+    // If the report is not an IOU, Expense report or an Invoice, it shouldn't be treated as one-transaction report.
     const report = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`];
     if (report?.type !== CONST.REPORT.TYPE.IOU && report?.type !== CONST.REPORT.TYPE.EXPENSE && report?.type !== CONST.REPORT.TYPE.INVOICE) {
         return null;
diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 686808f01611..d61945f506c8 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -675,9 +675,6 @@ function isChatReport(report: OnyxEntry<Report> | EmptyObject): boolean {
     return report?.type === CONST.REPORT.TYPE.CHAT;
 }
 
-/**
- * Checks if a report is an invoice report.
- */
 function isInvoiceReport(report: OnyxEntry<Report> | EmptyObject): boolean {
     return report?.type === CONST.REPORT.TYPE.INVOICE;
 }
@@ -869,9 +866,6 @@ function isPolicyExpenseChat(report: OnyxEntry<Report> | Participant | EmptyObje
     return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT || (report?.isPolicyExpenseChat ?? false);
 }
 
-/**
- * Whether the provided report is an invoice room chat.
- */
 function isInvoiceRoom(report: OnyxEntry<Report>): boolean {
     return getChatType(report) === CONST.REPORT.CHAT_TYPE.INVOICE;
 }

From 1a24b88541e18566469ced08faec407f7a2e5f2c Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 26 Apr 2024 10:26:38 +0200
Subject: [PATCH 55/58] restrict for request options invoice room

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

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index d61945f506c8..150c9c7aebaf 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -5270,7 +5270,7 @@ function isGroupChatAdmin(report: OnyxEntry<Report>, accountID: number) {
  */
 function getMoneyRequestOptions(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>, reportParticipants: number[], canUseTrackExpense = true, filterDeprecatedTypes = false): IOUType[] {
     // In any thread or task report, we do not allow any new expenses yet
-    if (isChatThread(report) || isTaskReport(report) || (!canUseTrackExpense && isSelfDM(report))) {
+    if (isChatThread(report) || isTaskReport(report) || (!canUseTrackExpense && isSelfDM(report)) || isInvoiceRoom(report)) {
         return [];
     }
 

From b024fe556c59a05dba78b8f79566a9199c1f6a56 Mon Sep 17 00:00:00 2001
From: Mykhailo Kravchenko <rezkiy37@gmail.com>
Date: Fri, 26 Apr 2024 10:34:15 +0200
Subject: [PATCH 56/58] restrict for request options invoice room

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

diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts
index 150c9c7aebaf..a558dd9b941b 100644
--- a/src/libs/ReportUtils.ts
+++ b/src/libs/ReportUtils.ts
@@ -5270,7 +5270,7 @@ function isGroupChatAdmin(report: OnyxEntry<Report>, accountID: number) {
  */
 function getMoneyRequestOptions(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>, reportParticipants: number[], canUseTrackExpense = true, filterDeprecatedTypes = false): IOUType[] {
     // In any thread or task report, we do not allow any new expenses yet
-    if (isChatThread(report) || isTaskReport(report) || (!canUseTrackExpense && isSelfDM(report)) || isInvoiceRoom(report)) {
+    if (isChatThread(report) || isTaskReport(report) || (!canUseTrackExpense && isSelfDM(report)) || isInvoiceRoom(report) || isInvoiceReport(report)) {
         return [];
     }
 

From ef395d2d4b351c0cb56e34500ad14ae3a6a026f9 Mon Sep 17 00:00:00 2001
From: Rocio Perez-Cano <rocio@expensify.com>
Date: Fri, 26 Apr 2024 12:30:28 +0200
Subject: [PATCH 57/58] Prettier

---
 config/webpack/webpack.dev.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/config/webpack/webpack.dev.ts b/config/webpack/webpack.dev.ts
index 4a004fb61d6d..7a196da6b691 100644
--- a/config/webpack/webpack.dev.ts
+++ b/config/webpack/webpack.dev.ts
@@ -23,7 +23,7 @@ const getConfiguration = (environment: Environment): Promise<Configuration> =>
                 : {
                       proxy: [
                           {
-                              context: ["/api", "/staging", "/chat-attachments", "/receipts"],
+                              context: ['/api', '/staging', '/chat-attachments', '/receipts'],
                               target: 'http://[::1]:9000',
                           },
                       ],

From 396447f1b601e7eb29063542dd7e1b74b2a86fc0 Mon Sep 17 00:00:00 2001
From: Cristi Paval <cristi@expensify.com>
Date: Fri, 26 Apr 2024 22:57:35 +0200
Subject: [PATCH 58/58] Fix TS issues

---
 .../ReportActionCompose/AttachmentPickerWithMenuItems.tsx    | 5 +++++
 src/pages/iou/request/IOURequestStartPage.tsx                | 1 +
 2 files changed, 6 insertions(+)

diff --git a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx
index 1adb161a92e9..924d9c5f1cd9 100644
--- a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx
+++ b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.tsx
@@ -147,6 +147,11 @@ function AttachmentPickerWithMenuItems({
                 text: translate('iou.trackExpense'),
                 onSelected: () => IOU.startMoneyRequest(CONST.IOU.TYPE.TRACK, report?.reportID ?? ''),
             },
+            [CONST.IOU.TYPE.INVOICE]: {
+                icon: Expensicons.Invoice,
+                text: translate('workspace.invoices.sendInvoice'),
+                onSelected: () => IOU.startMoneyRequest(CONST.IOU.TYPE.INVOICE, report?.reportID ?? ''),
+            },
         };
 
         return ReportUtils.temporary_getMoneyRequestOptions(report, policy, reportParticipantIDs ?? [], canUseTrackExpense).map((option) => ({
diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx
index 95c7b09ce1c1..db58e4220cba 100644
--- a/src/pages/iou/request/IOURequestStartPage.tsx
+++ b/src/pages/iou/request/IOURequestStartPage.tsx
@@ -67,6 +67,7 @@ function IOURequestStartPage({
         [CONST.IOU.TYPE.PAY]: translate('iou.paySomeone', {name: ReportUtils.getPayeeName(report)}),
         [CONST.IOU.TYPE.SPLIT]: translate('iou.splitExpense'),
         [CONST.IOU.TYPE.TRACK]: translate('iou.trackExpense'),
+        [CONST.IOU.TYPE.INVOICE]: translate('workspace.invoices.sendInvoice'),
     };
     const transactionRequestType = useRef(TransactionUtils.getRequestType(transaction));
     const {canUseP2PDistanceRequests} = usePermissions(iouType);