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);