From 4a4fef0eae681b40ccce46cc51114f9660795327 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 28 May 2024 14:26:16 +0200 Subject: [PATCH 1/7] include invoice room for participants --- src/components/MoneyRequestConfirmationList.tsx | 11 +++++++++-- src/libs/OptionsListUtils.ts | 16 ++++++++++++++-- .../request/MoneyRequestParticipantsSelector.tsx | 1 + 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 65a83090a05..ce5a18c6c3f 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -281,11 +281,18 @@ function MoneyRequestConfirmationList({ const policyTagLists = useMemo(() => PolicyUtils.getTagLists(policyTags), [policyTags]); const senderWorkspace = useMemo(() => { + const invoiceRoomParticipant = selectedParticipantsProp.find((participant) => participant.isInvoiceRoom); const senderWorkspaceParticipant = selectedParticipantsProp.find((participant) => participant.isSender); - return allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${senderWorkspaceParticipant?.policyID}`]; + const senderPolicyID = invoiceRoomParticipant?.policyID ?? senderWorkspaceParticipant?.policyID; + + return allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${senderPolicyID}`]; }, [allPolicies, selectedParticipantsProp]); - const canUpdateSenderWorkspace = useMemo(() => PolicyUtils.canSendInvoice(allPolicies) && !!transaction?.isFromGlobalCreate, [allPolicies, transaction?.isFromGlobalCreate]); + const canUpdateSenderWorkspace = useMemo(() => { + const isInvoiceRoomParticipant = selectedParticipantsProp.some((participant) => participant.isInvoiceRoom); + + return PolicyUtils.canSendInvoice(allPolicies) && !!transaction?.isFromGlobalCreate && !isInvoiceRoomParticipant; + }, [allPolicies, selectedParticipantsProp, transaction?.isFromGlobalCreate]); // A flag for showing the tags field // TODO: remove the !isTypeInvoice from this condition after BE supports tags for invoices: https://github.com/Expensify/App/issues/41281 diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 0d585476494..d59bea1f114 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -170,6 +170,7 @@ type GetOptionsConfig = { policyReportFieldOptions?: string[]; recentlyUsedPolicyReportFieldOptions?: string[]; transactionViolations?: OnyxCollection; + includeInvoiceRooms?: boolean; }; type GetUserToInviteConfig = { @@ -1691,6 +1692,7 @@ function getOptions( includePolicyReportFieldOptions = false, policyReportFieldOptions = [], recentlyUsedPolicyReportFieldOptions = [], + includeInvoiceRooms = false, }: GetOptionsConfig, ): Options { if (includeCategories) { @@ -1890,8 +1892,16 @@ function getOptions( const isCurrentUserOwnedPolicyExpenseChatThatCouldShow = reportOption.isPolicyExpenseChat && reportOption.ownerAccountID === currentUserAccountID && includeOwnedWorkspaceChats && !reportOption.isArchivedRoom; - // Skip if we aren't including multiple participant reports and this report has multiple participants - if (!isCurrentUserOwnedPolicyExpenseChatThatCouldShow && !includeMultipleParticipantReports && !reportOption.login) { + const shouldShowInvoiceRoom = includeInvoiceRooms && ReportUtils.isInvoiceRoom(reportOption.item); + + /** + Exclude the report option if it doesn't meet any of the following conditions: + - It is not an owned policy expense chat that could be shown + - Multiple participant reports are not included + - It doesn't have a login + - It is not an invoice room that should be shown + */ + if (!isCurrentUserOwnedPolicyExpenseChatThatCouldShow && !includeMultipleParticipantReports && !reportOption.login && !shouldShowInvoiceRoom) { continue; } @@ -2084,6 +2094,7 @@ function getFilteredOptions( recentlyUsedPolicyReportFieldOptions: string[] = [], includePersonalDetails = true, maxRecentReportsToShow = 5, + includeInvoiceRooms = false, ) { return getOptions( {reports, personalDetails}, @@ -2111,6 +2122,7 @@ function getFilteredOptions( includePolicyReportFieldOptions, policyReportFieldOptions, recentlyUsedPolicyReportFieldOptions, + includeInvoiceRooms, }, ); } diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index b525a2c1e3d..34cfb2eb186 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -117,6 +117,7 @@ function MoneyRequestParticipantsSelector({participants = [], onFinish, onPartic undefined, !isCategorizeOrShareAction, isCategorizeOrShareAction ? 0 : undefined, + iouType === CONST.IOU.TYPE.INVOICE, ); const formatResults = OptionsListUtils.formatSectionsFromSearchTerm( From 72eae40af92d571caa770cdfb937d016b833bbec Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 28 May 2024 18:39:40 +0200 Subject: [PATCH 2/7] Add Report type to Participant item --- src/types/onyx/IOU.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts index 68e8836e149..7b439467f7b 100644 --- a/src/types/onyx/IOU.ts +++ b/src/types/onyx/IOU.ts @@ -1,6 +1,7 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; import type {Icon} from './OnyxCommon'; +import type Report from './Report'; type Participant = { accountID?: number; @@ -26,6 +27,7 @@ type Participant = { isSender?: boolean; iouType?: string; ownerAccountID?: number; + item?: Report; }; type Split = { From a7aa13a084e53a142e3739b64d1d5a3ec5cb06f2 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 28 May 2024 18:40:10 +0200 Subject: [PATCH 3/7] integrate participant handling --- src/pages/iou/request/MoneyRequestParticipantsSelector.tsx | 6 +++--- src/pages/iou/request/step/IOURequestStepParticipants.tsx | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index 34cfb2eb186..2caed9f19a0 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -22,6 +22,7 @@ import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import type {MaybePhraseKey} from '@libs/Localize'; import type {Options} from '@libs/OptionsListUtils'; import * as OptionsListUtils from '@libs/OptionsListUtils'; +import * as ReportUtils from '@libs/ReportUtils'; import * as Policy from '@userActions/Policy'; import * as Report from '@userActions/Report'; import type {IOUAction, IOURequestType, IOUType} from '@src/CONST'; @@ -191,10 +192,9 @@ function MoneyRequestParticipantsSelector({participants = [], onFinish, onPartic ]; if (iouType === CONST.IOU.TYPE.INVOICE) { - const primaryPolicy = Policy.getPrimaryPolicy(activePolicyID); - + const policyID = ReportUtils.isInvoiceRoom(option.item) ? option.policyID : Policy.getPrimaryPolicy(activePolicyID)?.id; newParticipants.push({ - policyID: primaryPolicy?.id, + policyID, isSender: true, selected: false, iouType, diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index 89c6a4043b2..9c6601a84c0 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -94,7 +94,7 @@ function IOURequestStepParticipants({ // When multiple participants are selected, the reportID is generated at the end of the confirmation step. // So we are resetting selectedReportID ref to the reportID coming from params. - if (val.length !== 1) { + if (val.length !== 1 && iouType !== CONST.IOU.TYPE.INVOICE) { selectedReportID.current = reportID; return; } @@ -102,7 +102,7 @@ function IOURequestStepParticipants({ // When a participant is selected, the reportID needs to be saved because that's the reportID that will be used in the confirmation step. selectedReportID.current = val[0]?.reportID ?? reportID; }, - [reportID, transactionID], + [iouType, reportID, transactionID], ); const goToNextStep = useCallback(() => { From f99563cc70db7797c8637ebc799ad2033713c2ce Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 28 May 2024 18:44:13 +0200 Subject: [PATCH 4/7] simplify --- src/components/MoneyRequestConfirmationList.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index ce5a18c6c3f..faa5175f663 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -281,11 +281,8 @@ function MoneyRequestConfirmationList({ const policyTagLists = useMemo(() => PolicyUtils.getTagLists(policyTags), [policyTags]); const senderWorkspace = useMemo(() => { - const invoiceRoomParticipant = selectedParticipantsProp.find((participant) => participant.isInvoiceRoom); const senderWorkspaceParticipant = selectedParticipantsProp.find((participant) => participant.isSender); - const senderPolicyID = invoiceRoomParticipant?.policyID ?? senderWorkspaceParticipant?.policyID; - - return allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${senderPolicyID}`]; + return allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${senderWorkspaceParticipant?.policyID}`]; }, [allPolicies, selectedParticipantsProp]); const canUpdateSenderWorkspace = useMemo(() => { From 3c7886b0d6f74a46a7ed93e87e4d8c6c9cd7e3d7 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 29 May 2024 10:56:50 +0200 Subject: [PATCH 5/7] fix --- src/pages/iou/request/MoneyRequestParticipantsSelector.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx index b23a66662d4..9abf0ab1459 100644 --- a/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx +++ b/src/pages/iou/request/MoneyRequestParticipantsSelector.tsx @@ -192,7 +192,7 @@ function MoneyRequestParticipantsSelector({participants = [], onFinish, onPartic ]; if (iouType === CONST.IOU.TYPE.INVOICE) { - const policyID = ReportUtils.isInvoiceRoom(option.item) ? option.policyID : Policy.getPrimaryPolicy(activePolicyID)?.id; + const policyID = option.item && ReportUtils.isInvoiceRoom(option.item) ? option.policyID : Policy.getPrimaryPolicy(activePolicyID)?.id; newParticipants.push({ policyID, isSender: true, From 0364669b7527d72109b762f988ac8618de62c8f6 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 29 May 2024 16:09:51 +0200 Subject: [PATCH 6/7] show invoice room only for admins --- src/libs/OptionsListUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils.ts b/src/libs/OptionsListUtils.ts index 03cf34e3354..d3cb8eeec2e 100644 --- a/src/libs/OptionsListUtils.ts +++ b/src/libs/OptionsListUtils.ts @@ -1889,7 +1889,7 @@ function getOptions( const isCurrentUserOwnedPolicyExpenseChatThatCouldShow = reportOption.isPolicyExpenseChat && reportOption.ownerAccountID === currentUserAccountID && includeOwnedWorkspaceChats && !reportOption.isArchivedRoom; - const shouldShowInvoiceRoom = includeInvoiceRooms && ReportUtils.isInvoiceRoom(reportOption.item); + const shouldShowInvoiceRoom = includeInvoiceRooms && ReportUtils.isInvoiceRoom(reportOption.item) && ReportUtils.isPolicyAdmin(reportOption.policyID ?? '', policies); /** Exclude the report option if it doesn't meet any of the following conditions: From 1455e033300f8e913a4c51052d69cd5cea7d629c Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 29 May 2024 16:23:32 +0200 Subject: [PATCH 7/7] use participant report id for invoice room only --- .../iou/request/step/IOURequestStepParticipants.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx index 8131f3b2667..5a9d7cfd233 100644 --- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx +++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx @@ -84,21 +84,23 @@ function IOURequestStepParticipants({ const addParticipant = useCallback( (val: Participant[]) => { + const firstParticipantReportID = val[0]?.reportID ?? ''; + const rateID = DistanceRequestUtils.getCustomUnitRateID(firstParticipantReportID); + const isInvoice = iouType === CONST.IOU.TYPE.INVOICE && ReportUtils.isInvoiceRoom(ReportUtils.getReport(firstParticipantReportID)); + numberOfParticipants.current = val.length; + IOU.setMoneyRequestParticipants(transactionID, val); - const rateID = DistanceRequestUtils.getCustomUnitRateID(val[0]?.reportID ?? ''); IOU.setCustomUnitRateID(transactionID, rateID); - numberOfParticipants.current = val.length; - // When multiple participants are selected, the reportID is generated at the end of the confirmation step. // So we are resetting selectedReportID ref to the reportID coming from params. - if (val.length !== 1 && iouType !== CONST.IOU.TYPE.INVOICE) { + if (val.length !== 1 && !isInvoice) { selectedReportID.current = reportID; return; } // When a participant is selected, the reportID needs to be saved because that's the reportID that will be used in the confirmation step. - selectedReportID.current = val[0]?.reportID ?? reportID; + selectedReportID.current = firstParticipantReportID || reportID; }, [iouType, reportID, transactionID], );