From 9229520889e84d7d54be9e9d7c24c8813a2a9204 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 23 May 2024 09:44:21 +0200 Subject: [PATCH 01/14] Support invoice paying as business --- src/components/MoneyReportHeader.tsx | 4 +- .../ReportActionItem/ReportPreview.tsx | 4 +- src/components/SettlementButton.tsx | 23 ++++++++++- src/libs/API/parameters/PayInvoiceParams.ts | 1 + src/libs/ReportUtils.ts | 5 +++ src/libs/actions/IOU.ts | 38 +++++++++++++------ src/libs/actions/Policy/Policy.ts | 2 +- 7 files changed, 60 insertions(+), 17 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index ec52a6158ad..43b2ca6729e 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -119,7 +119,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea const displayedAmount = ReportUtils.hasHeldExpenses(moneyRequestReport.reportID) && canAllowSettlement ? nonHeldAmount : formattedAmount; const isMoreContentShown = shouldShowNextStep || hasScanningReceipt || (shouldShowAnyButton && shouldUseNarrowLayout); - const confirmPayment = (type?: PaymentMethodType | undefined) => { + const confirmPayment = (type?: PaymentMethodType | undefined, payAsBusiness?: boolean) => { if (!type || !chatReport) { return; } @@ -128,7 +128,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea if (ReportUtils.hasHeldExpenses(moneyRequestReport.reportID)) { setIsHoldMenuVisible(true); } else if (ReportUtils.isInvoiceReport(moneyRequestReport)) { - IOU.payInvoice(type, chatReport, moneyRequestReport); + IOU.payInvoice(type, chatReport, moneyRequestReport, payAsBusiness); } else { IOU.payMoneyRequest(type, chatReport, moneyRequestReport, true); } diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 4677563d204..abdb963530d 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -280,12 +280,12 @@ function ReportPreview({ }; }, [formattedMerchant, formattedDescription, moneyRequestComment, translate, numberOfRequests, numberOfScanningReceipts, numberOfPendingRequests]); - const confirmPayment = (paymentMethodType?: PaymentMethodType) => { + const confirmPayment = (paymentMethodType?: PaymentMethodType, payAsBusiness?: boolean) => { if (!paymentMethodType || !chatReport || !iouReport) { return; } if (ReportUtils.isInvoiceReport(iouReport)) { - IOU.payInvoice(paymentMethodType, chatReport, iouReport); + IOU.payInvoice(paymentMethodType, chatReport, iouReport, payAsBusiness); } else { IOU.payMoneyRequest(paymentMethodType, chatReport, iouReport); } diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index b6e2a753c82..c5eaa0dec33 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -1,14 +1,16 @@ import React, {useEffect, useMemo} from 'react'; import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx, withOnyx} from 'react-native-onyx'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import playSound, {SOUNDS} from '@libs/Sound'; import * as BankAccounts from '@userActions/BankAccounts'; import * as IOU from '@userActions/IOU'; import * as PaymentMethods from '@userActions/PaymentMethods'; +import * as PolicyActions from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; @@ -143,6 +145,9 @@ function SettlementButton({ }: SettlementButtonProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); + const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); + + const primaryPolicy = useMemo(() => PolicyActions.getPrimaryPolicy(activePolicyID) ?? null, [activePolicyID]); useEffect(() => { PaymentMethods.openWalletPage(); @@ -216,6 +221,22 @@ function SettlementButton({ }, ], }); + + if (PolicyUtils.isPolicyAdmin(primaryPolicy)) { + buttonOptions.push({ + text: translate('iou.settleBusiness', {formattedAmount}), + icon: Expensicons.Building, + value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + subMenuItems: [ + { + text: translate('iou.payElsewhere', {formattedAmount: ''}), + icon: Expensicons.Cash, + value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + onSelected: () => onPress(CONST.IOU.PAYMENT_TYPE.ELSEWHERE, true), + }, + ], + }); + } } if (shouldShowApproveButton) { diff --git a/src/libs/API/parameters/PayInvoiceParams.ts b/src/libs/API/parameters/PayInvoiceParams.ts index 4c6633749ad..a6b9746d87b 100644 --- a/src/libs/API/parameters/PayInvoiceParams.ts +++ b/src/libs/API/parameters/PayInvoiceParams.ts @@ -4,6 +4,7 @@ type PayInvoiceParams = { reportID: string; reportActionID: string; paymentMethodType: PaymentMethodType; + payAsBusiness: boolean; }; export default PayInvoiceParams; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 7e99c60cb61..7f06ebad860 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -905,6 +905,10 @@ function isInvoiceRoom(report: OnyxEntry | EmptyObject): boolean { return getChatType(report) === CONST.REPORT.CHAT_TYPE.INVOICE; } +function isIndividualInvoiceRoom(report: OnyxEntry): boolean { + return isInvoiceRoom(report) && report?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL; +} + function isCurrentUserInvoiceReceiver(report: OnyxEntry): boolean { if (report?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL) { return currentUserAccountID === report.invoiceReceiver.accountID; @@ -7065,6 +7069,7 @@ export { isCurrentUserInvoiceReceiver, isDraftReport, createDraftWorkspaceAndNavigateToConfirmationScreen, + isIndividualInvoiceRoom, }; export type { diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index a98a9c31517..6e8d065fb62 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -285,6 +285,12 @@ Onyx.connect({ }, }); +let primaryPolicyID: OnyxEntry; +Onyx.connect({ + key: ONYXKEYS.NVP_ACTIVE_POLICY_ID, + callback: (value) => (primaryPolicyID = value), +}); + /** * Find the report preview action from given chat report and iou report */ @@ -5850,6 +5856,7 @@ function getPayMoneyRequestParams( recipient: Participant, paymentMethodType: PaymentMethodType, full: boolean, + payAsBusiness?: boolean, ): PayMoneyRequestData { const isInvoiceReport = ReportUtils.isInvoiceReport(iouReport); @@ -5884,19 +5891,27 @@ function getPayMoneyRequestParams( optimisticNextStep = NextStepUtils.buildNextStep(iouReport, CONST.REPORT.STATUS_NUM.REIMBURSED, {isPaidWithExpensify: paymentMethodType === CONST.IOU.PAYMENT_TYPE.VBBA}); } + const optimisticChatReport = { + ...chatReport, + lastReadTime: DateUtils.getDBTime(), + lastVisibleActionCreated: optimisticIOUReportAction.created, + hasOutstandingChildRequest: false, + iouReportID: null, + lastMessageText: optimisticIOUReportAction.message?.[0]?.text, + lastMessageHtml: optimisticIOUReportAction.message?.[0]?.html, + }; + if (ReportUtils.isIndividualInvoiceRoom(chatReport) && payAsBusiness && primaryPolicyID) { + optimisticChatReport.invoiceReceiver = { + type: CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS, + policyID: primaryPolicyID, + }; + } + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, - value: { - ...chatReport, - lastReadTime: DateUtils.getDBTime(), - lastVisibleActionCreated: optimisticIOUReportAction.created, - hasOutstandingChildRequest: false, - iouReportID: null, - lastMessageText: optimisticIOUReportAction.message?.[0]?.text, - lastMessageHtml: optimisticIOUReportAction.message?.[0]?.html, - }, + value: optimisticChatReport, }, { onyxMethod: Onyx.METHOD.MERGE, @@ -6495,19 +6510,20 @@ function payMoneyRequest(paymentType: PaymentMethodType, chatReport: OnyxTypes.R Navigation.dismissModalWithReport(chatReport); } -function payInvoice(paymentMethodType: PaymentMethodType, chatReport: OnyxTypes.Report, invoiceReport: OnyxTypes.Report) { +function payInvoice(paymentMethodType: PaymentMethodType, chatReport: OnyxTypes.Report, invoiceReport: OnyxTypes.Report, payAsBusiness = false) { const recipient = {accountID: invoiceReport.ownerAccountID}; const { optimisticData, successData, failureData, params: {reportActionID}, - } = getPayMoneyRequestParams(chatReport, invoiceReport, recipient, paymentMethodType, true); + } = getPayMoneyRequestParams(chatReport, invoiceReport, recipient, paymentMethodType, true, payAsBusiness); const params: PayInvoiceParams = { reportID: invoiceReport.reportID, reportActionID, paymentMethodType, + payAsBusiness, }; API.write(WRITE_COMMANDS.PAY_INVOICE, params, {optimisticData, successData, failureData}); diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts index 4d918352ba9..f3d152d81c4 100644 --- a/src/libs/actions/Policy/Policy.ts +++ b/src/libs/actions/Policy/Policy.ts @@ -235,7 +235,7 @@ function getPolicy(policyID: string | undefined): Policy | EmptyObject { */ function getPrimaryPolicy(activePolicyID?: OnyxEntry): Policy | undefined { const activeAdminWorkspaces = PolicyUtils.getActiveAdminWorkspaces(allPolicies); - const primaryPolicy: Policy | null | undefined = allPolicies?.[activePolicyID ?? '']; + const primaryPolicy: Policy | null | undefined = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`]; return primaryPolicy ?? activeAdminWorkspaces[0]; } From 7f6e6eb93d212a88964851efa876122a10549adb Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 24 May 2024 14:33:03 +0200 Subject: [PATCH 02/14] UI updates to support B2B invoices rooms --- .../ReportActionItem/ReportPreview.tsx | 12 +++- src/libs/ReportUtils.ts | 70 ++++++++++++++++++- .../home/report/ReportActionItemSingle.tsx | 20 +----- 3 files changed, 80 insertions(+), 22 deletions(-) diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index abdb963530d..36831e26291 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -125,6 +125,7 @@ function ReportPreview({ const iouSettled = ReportUtils.isSettled(iouReportID); const moneyRequestComment = action?.childLastMoneyRequestComment ?? ''; const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(chatReport); + const isInvoiceRoom = ReportUtils.isInvoiceRoom(chatReport); const isOpenExpenseReport = isPolicyExpenseChat && ReportUtils.isOpenExpenseReport(iouReport); const isApproved = ReportUtils.isReportApproved(iouReport); @@ -205,7 +206,16 @@ function ReportPreview({ if (isScanning) { return translate('common.receipt'); } - let payerOrApproverName = isPolicyExpenseChat ? ReportUtils.getPolicyName(chatReport) : ReportUtils.getDisplayNameForParticipant(managerID, true); + + let payerOrApproverName; + if (isPolicyExpenseChat) { + payerOrApproverName = ReportUtils.getPolicyName(chatReport); + } else if (isInvoiceRoom) { + payerOrApproverName = ReportUtils.getInvoicePayerName(chatReport); + } else { + payerOrApproverName = ReportUtils.getDisplayNameForParticipant(managerID, true); + } + if (isApproved) { return translate('iou.managerApproved', {manager: payerOrApproverName}); } diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 7f06ebad860..b2a18925c9b 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -914,6 +914,11 @@ function isCurrentUserInvoiceReceiver(report: OnyxEntry): boolean { return currentUserAccountID === report.invoiceReceiver.accountID; } + if (report?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS) { + const policy = PolicyUtils.getPolicy(report.invoiceReceiver.policyID); + return PolicyUtils.isPolicyAdmin(policy); + } + return false; } @@ -1855,6 +1860,45 @@ function getDisplayNameForParticipant(accountID?: number, shouldUseShortForm = f return shouldUseShortForm ? shortName : longName; } +function getSecondaryAvatar(chatReport: OnyxEntry, iouReport: OnyxEntry, displayAllActors: boolean, isWorkspaceActor: boolean, actorAccountID?: number): Icon { + let secondaryAvatar: Icon; + + if (displayAllActors) { + if (!isIndividualInvoiceRoom(chatReport)) { + const secondaryPolicyID = chatReport?.invoiceReceiver && 'policyID' in chatReport.invoiceReceiver ? chatReport.invoiceReceiver.policyID : '-1'; + const secondaryPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${secondaryPolicyID}`]; + const avatar = secondaryPolicy?.avatarURL ?? getDefaultWorkspaceAvatar(secondaryPolicy?.name); + + secondaryAvatar = { + source: avatar, + type: CONST.ICON_TYPE_WORKSPACE, + name: secondaryPolicy?.name, + id: secondaryPolicyID, + }; + } else { + const secondaryAccountId = iouReport?.ownerAccountID === actorAccountID || isInvoiceReport(iouReport) ? iouReport?.managerID : iouReport?.ownerAccountID; + const secondaryUserAvatar = allPersonalDetails?.[secondaryAccountId ?? -1]?.avatar ?? ''; + const secondaryDisplayName = getDisplayNameForParticipant(secondaryAccountId); + + secondaryAvatar = { + source: UserUtils.getAvatar(secondaryUserAvatar, secondaryAccountId), + type: CONST.ICON_TYPE_AVATAR, + name: secondaryDisplayName ?? '', + id: secondaryAccountId, + }; + } + } else if (!isWorkspaceActor) { + const avatarIconIndex = chatReport?.isOwnPolicyExpenseChat || isPolicyExpenseChat(chatReport) ? 0 : 1; + const reportIcons = getIcons(chatReport, {}); + + secondaryAvatar = reportIcons[avatarIconIndex]; + } else { + secondaryAvatar = {name: '', source: '', type: 'avatar'}; + } + + return secondaryAvatar; +} + function getParticipantAccountIDs(reportID: string) { const report = getReport(reportID); if (!report || !report.participants) { @@ -2018,7 +2062,12 @@ function getIcons( } else { const receiverPolicy = getPolicy(report?.invoiceReceiver?.policyID); if (!isEmptyObject(receiverPolicy)) { - icons.push(getWorkspaceIcon(report, receiverPolicy)); + icons.push({ + source: receiverPolicy?.avatarURL ?? getDefaultWorkspaceAvatar(receiverPolicy.name), + type: CONST.ICON_TYPE_WORKSPACE, + name: receiverPolicy.name, + id: receiverPolicy.id, + }); } } } @@ -2093,7 +2142,12 @@ function getIcons( const receiverPolicy = getPolicy(invoiceRoomReport?.invoiceReceiver?.policyID); if (!isEmptyObject(receiverPolicy)) { - icons.push(getWorkspaceIcon(invoiceRoomReport, receiverPolicy)); + icons.push({ + source: receiverPolicy?.avatarURL ?? getDefaultWorkspaceAvatar(receiverPolicy.name), + type: CONST.ICON_TYPE_WORKSPACE, + name: receiverPolicy.name, + id: receiverPolicy.id, + }); } return icons; @@ -2531,7 +2585,16 @@ function getMoneyRequestReportName(report: OnyxEntry, policy: OnyxEntry< const moneyRequestTotal = getMoneyRequestSpendBreakdown(report).totalDisplaySpend; const formattedAmount = CurrencyUtils.convertToDisplayString(moneyRequestTotal, report?.currency); - let payerOrApproverName = isExpenseReport(report) ? getPolicyName(report, false, policy) : getDisplayNameForParticipant(report?.managerID) ?? ''; + let payerOrApproverName; + if (isExpenseReport(report)) { + payerOrApproverName = getPolicyName(report, false, policy); + } else if (isInvoiceReport(report)) { + const chatReport = getReport(report?.chatReportID); + payerOrApproverName = getInvoicePayerName(chatReport); + } else { + payerOrApproverName = getDisplayNameForParticipant(report?.managerID) ?? ''; + } + const payerPaidAmountMessage = Localize.translateLocal('iou.payerPaidAmount', { payer: payerOrApproverName, amount: formattedAmount, @@ -7070,6 +7133,7 @@ export { isDraftReport, createDraftWorkspaceAndNavigateToConfirmationScreen, isIndividualInvoiceRoom, + getSecondaryAvatar, }; export type { diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index f71db06c2d4..e6a87087959 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -84,7 +84,7 @@ 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.REPORT_PREVIEW && iouReport, [action?.actionName, iouReport]); + const displayAllActors = useMemo(() => action?.actionName === CONST.REPORT.ACTIONS.TYPE.REPORT_PREVIEW && !!iouReport, [action?.actionName, iouReport]); const isInvoiceReport = ReportUtils.isInvoiceReport(iouReport ?? {}); const isWorkspaceActor = isInvoiceReport || (ReportUtils.isPolicyExpenseChat(report) && (!actorAccountID || displayAllActors)); let avatarSource = avatar; @@ -107,32 +107,16 @@ function ReportActionItemSingle({ } // If this is a report preview, display names and avatars of both people involved - let secondaryAvatar: Icon; + const secondaryAvatar = ReportUtils.getSecondaryAvatar(report, iouReport ?? null, displayAllActors, isWorkspaceActor, actorAccountID); const primaryDisplayName = displayName; if (displayAllActors) { // The ownerAccountID and actorAccountID can be the same if the user submits an expense back from the IOU's original creator, in that case we need to use managerID to avoid displaying the same user twice const secondaryAccountId = iouReport?.ownerAccountID === actorAccountID || isInvoiceReport ? iouReport?.managerID : iouReport?.ownerAccountID; - const secondaryUserAvatar = personalDetails?.[secondaryAccountId ?? -1]?.avatar ?? FallbackAvatar; const secondaryDisplayName = ReportUtils.getDisplayNameForParticipant(secondaryAccountId); if (!isInvoiceReport) { displayName = `${primaryDisplayName} & ${secondaryDisplayName}`; } - - secondaryAvatar = { - source: secondaryUserAvatar, - type: CONST.ICON_TYPE_AVATAR, - name: secondaryDisplayName ?? '', - id: secondaryAccountId, - }; - } else if (!isWorkspaceActor) { - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const avatarIconIndex = report.isOwnPolicyExpenseChat || ReportUtils.isPolicyExpenseChat(report) ? 0 : 1; - const reportIcons = ReportUtils.getIcons(report, {}); - - secondaryAvatar = reportIcons[avatarIconIndex]; - } else { - secondaryAvatar = {name: '', source: '', type: 'avatar'}; } const icon = { source: avatarSource ?? FallbackAvatar, From 506482133b00fc16f1e9bf82f331b48e5bc6127d Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 4 Jun 2024 16:35:35 +0200 Subject: [PATCH 03/14] Minor improvements --- src/components/SettlementButton.tsx | 4 ++-- src/libs/ReportUtils.ts | 9 +++++---- src/pages/home/report/ReportActionItemSingle.tsx | 1 - 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index c5eaa0dec33..62b0c2ee89a 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -43,7 +43,7 @@ type SettlementButtonOnyxProps = { type SettlementButtonProps = SettlementButtonOnyxProps & { /** Callback to execute when this button is pressed. Receives a single payment type argument. */ - onPress: (paymentType?: PaymentMethodType) => void; + onPress: (paymentType?: PaymentMethodType, payAsBusiness?: boolean) => void; /** The route to redirect if user does not have a payment method setup */ enablePaymentsRoute: EnablePaymentsRoute; @@ -278,7 +278,7 @@ function SettlementButton({ return ( onPress(paymentType)} enablePaymentsRoute={enablePaymentsRoute} addBankAccountRoute={addBankAccountRoute} addDebitCardRoute={addDebitCardRoute} diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b2a18925c9b..68f1cf9c830 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1867,21 +1867,22 @@ function getSecondaryAvatar(chatReport: OnyxEntry, iouReport: OnyxEntry< if (!isIndividualInvoiceRoom(chatReport)) { const secondaryPolicyID = chatReport?.invoiceReceiver && 'policyID' in chatReport.invoiceReceiver ? chatReport.invoiceReceiver.policyID : '-1'; const secondaryPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${secondaryPolicyID}`]; - const avatar = secondaryPolicy?.avatarURL ?? getDefaultWorkspaceAvatar(secondaryPolicy?.name); + const secondaryPolicyAvatar = secondaryPolicy?.avatarURL ?? getDefaultWorkspaceAvatar(secondaryPolicy?.name); secondaryAvatar = { - source: avatar, + source: secondaryPolicyAvatar, type: CONST.ICON_TYPE_WORKSPACE, name: secondaryPolicy?.name, id: secondaryPolicyID, }; } else { + // The ownerAccountID and actorAccountID can be the same if the user submits an expense back from the IOU's original creator, in that case we need to use managerID to avoid displaying the same user twice const secondaryAccountId = iouReport?.ownerAccountID === actorAccountID || isInvoiceReport(iouReport) ? iouReport?.managerID : iouReport?.ownerAccountID; - const secondaryUserAvatar = allPersonalDetails?.[secondaryAccountId ?? -1]?.avatar ?? ''; + const secondaryUserAvatar = allPersonalDetails?.[secondaryAccountId ?? -1]?.avatar ?? FallbackAvatar; const secondaryDisplayName = getDisplayNameForParticipant(secondaryAccountId); secondaryAvatar = { - source: UserUtils.getAvatar(secondaryUserAvatar, secondaryAccountId), + source: secondaryUserAvatar, type: CONST.ICON_TYPE_AVATAR, name: secondaryDisplayName ?? '', id: secondaryAccountId, diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index e6a87087959..eee4f570ef1 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -23,7 +23,6 @@ import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Report, ReportAction} from '@src/types/onyx'; -import type {Icon} from '@src/types/onyx/OnyxCommon'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import ReportActionItemDate from './ReportActionItemDate'; import ReportActionItemFragment from './ReportActionItemFragment'; From 74e0b2510b903952acfd601de4436e1dc52aebed Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 4 Jun 2024 16:59:50 +0200 Subject: [PATCH 04/14] Lint fix --- 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 68f1cf9c830..2569bc56a33 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1889,7 +1889,7 @@ function getSecondaryAvatar(chatReport: OnyxEntry, iouReport: OnyxEntry< }; } } else if (!isWorkspaceActor) { - const avatarIconIndex = chatReport?.isOwnPolicyExpenseChat || isPolicyExpenseChat(chatReport) ? 0 : 1; + const avatarIconIndex = !!chatReport?.isOwnPolicyExpenseChat || isPolicyExpenseChat(chatReport) ? 0 : 1; const reportIcons = getIcons(chatReport, {}); secondaryAvatar = reportIcons[avatarIconIndex]; From 1ea212ef4c480260dea571b1aaf881e08413f956 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 7 Jun 2024 12:01:49 +0200 Subject: [PATCH 05/14] Minor UI fixes --- src/components/SettlementButton.tsx | 1 + src/languages/en.ts | 1 + src/languages/es.ts | 1 + src/libs/ReportUtils.ts | 10 ++++++---- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 62b0c2ee89a..d06d514d565 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -227,6 +227,7 @@ function SettlementButton({ text: translate('iou.settleBusiness', {formattedAmount}), icon: Expensicons.Building, value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + backButtonText: translate('iou.business'), subMenuItems: [ { text: translate('iou.payElsewhere', {formattedAmount: ''}), diff --git a/src/languages/en.ts b/src/languages/en.ts index 71148ce876e..5cfa2a165fd 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -679,6 +679,7 @@ export default { settledExpensify: 'Paid', settledElsewhere: 'Paid elsewhere', individual: 'Individual', + business: 'Business', settleExpensify: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} with Expensify` : `Pay with Expensify`), settlePersonal: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} as an individual` : `Pay as an individual`), settlePayment: ({formattedAmount}: SettleExpensifyCardParams) => `Pay ${formattedAmount}`, diff --git a/src/languages/es.ts b/src/languages/es.ts index 0e88abd1886..275184d6d5a 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -673,6 +673,7 @@ export default { settledExpensify: 'Pagado', settledElsewhere: 'Pagado de otra forma', individual: 'Individual', + business: 'Empresa', settleExpensify: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pagar ${formattedAmount} con Expensify` : `Pagar con Expensify`), settlePersonal: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pago ${formattedAmount} como individuo` : `Pago individual`), settlePayment: ({formattedAmount}: SettleExpensifyCardParams) => `Pagar ${formattedAmount}`, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index d53f0ba2186..8681f52d253 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2074,13 +2074,14 @@ function getIcons( if (report?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL) { icons.push(...getIconsForParticipants([report?.invoiceReceiver.accountID], personalDetails)); } else { - const receiverPolicy = getPolicy(report?.invoiceReceiver?.policyID); + const receiverPolicyID = report?.invoiceReceiver?.policyID; + const receiverPolicy = getPolicy(receiverPolicyID); if (!isEmptyObject(receiverPolicy)) { icons.push({ source: receiverPolicy?.avatarURL ?? getDefaultWorkspaceAvatar(receiverPolicy.name), type: CONST.ICON_TYPE_WORKSPACE, name: receiverPolicy.name, - id: receiverPolicy.id, + id: receiverPolicyID, }); } } @@ -2153,14 +2154,15 @@ function getIcons( return icons; } - const receiverPolicy = getPolicy(invoiceRoomReport?.invoiceReceiver?.policyID); + const receiverPolicyID = invoiceRoomReport?.invoiceReceiver?.policyID; + const receiverPolicy = getPolicy(receiverPolicyID); if (!isEmptyObject(receiverPolicy)) { icons.push({ source: receiverPolicy?.avatarURL ?? getDefaultWorkspaceAvatar(receiverPolicy.name), type: CONST.ICON_TYPE_WORKSPACE, name: receiverPolicy.name, - id: receiverPolicy.id, + id: receiverPolicyID, }); } From 97bf8d647d2caa81cce8d2bd51f45a0edb4a3fec Mon Sep 17 00:00:00 2001 From: VickyStash Date: Mon, 10 Jun 2024 10:07:04 +0200 Subject: [PATCH 06/14] Improve the check --- 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 8681f52d253..3ae370112a0 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1872,7 +1872,7 @@ function getSecondaryAvatar(chatReport: OnyxEntry, iouReport: OnyxEntry< let secondaryAvatar: Icon; if (displayAllActors) { - if (!isIndividualInvoiceRoom(chatReport)) { + if (isInvoiceRoom(chatReport) && !isIndividualInvoiceRoom(chatReport)) { const secondaryPolicyID = chatReport?.invoiceReceiver && 'policyID' in chatReport.invoiceReceiver ? chatReport.invoiceReceiver.policyID : '-1'; const secondaryPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${secondaryPolicyID}`]; const secondaryPolicyAvatar = secondaryPolicy?.avatarURL ?? getDefaultWorkspaceAvatar(secondaryPolicy?.name); From ef5f19b413715ca2c5931f7cc98d99fb6c24f4c8 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 13 Jun 2024 08:38:26 +0200 Subject: [PATCH 07/14] Fix ts error --- src/pages/home/report/ReportActionItemSingle.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index b537d43e3df..51d1df35f9a 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -106,7 +106,7 @@ function ReportActionItemSingle({ } // If this is a report preview, display names and avatars of both people involved - const secondaryAvatar = ReportUtils.getSecondaryAvatar(report, iouReport ?? null, displayAllActors, isWorkspaceActor, actorAccountID); + const secondaryAvatar = ReportUtils.getSecondaryAvatar(report, iouReport, displayAllActors, isWorkspaceActor, actorAccountID); const primaryDisplayName = displayName; if (displayAllActors) { // The ownerAccountID and actorAccountID can be the same if the user submits an expense back from the IOU's original creator, in that case we need to use managerID to avoid displaying the same user twice From db1aa8a488fe60f4bb73936c860ec01ba774586e Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 14 Jun 2024 10:27:52 +0200 Subject: [PATCH 08/14] Minor fix --- src/pages/iou/request/step/IOURequestStepConfirmation.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx index 1683ef3e3df..55cd658b4af 100644 --- a/src/pages/iou/request/step/IOURequestStepConfirmation.tsx +++ b/src/pages/iou/request/step/IOURequestStepConfirmation.tsx @@ -139,7 +139,7 @@ function IOURequestStepConfirmation({ const participants = useMemo( () => transaction?.participants?.map((participant) => { - const participantAccountID = participant.accountID ?? -1; + const participantAccountID = participant.accountID; if (participant.isSender && iouType === CONST.IOU.TYPE.INVOICE) { return participant; From aa9bd53c3907b4371c9cc7c56f43428b52c74bbf Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 14 Jun 2024 15:34:25 +0200 Subject: [PATCH 09/14] Hide Pay as individual option in B2B room --- src/components/SettlementButton.tsx | 32 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index b1386e1a6fa..de1197c78f3 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -202,20 +202,22 @@ function SettlementButton({ } if (isInvoiceReport) { - buttonOptions.push({ - text: translate('iou.settlePersonal', {formattedAmount}), - icon: Expensicons.User, - value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, - backButtonText: translate('iou.individual'), - subMenuItems: [ - { - text: translate('iou.payElsewhere', {formattedAmount: ''}), - icon: Expensicons.Cash, - value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, - onSelected: () => onPress(CONST.IOU.PAYMENT_TYPE.ELSEWHERE), - }, - ], - }); + if (ReportUtils.isIndividualInvoiceRoom(chatReport)) { + buttonOptions.push({ + text: translate('iou.settlePersonal', {formattedAmount}), + icon: Expensicons.User, + value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + backButtonText: translate('iou.individual'), + subMenuItems: [ + { + text: translate('iou.payElsewhere', {formattedAmount: ''}), + icon: Expensicons.Cash, + value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + onSelected: () => onPress(CONST.IOU.PAYMENT_TYPE.ELSEWHERE), + }, + ], + }); + } if (PolicyUtils.isPolicyAdmin(primaryPolicy)) { buttonOptions.push({ @@ -246,7 +248,7 @@ function SettlementButton({ return buttonOptions; // We don't want to reorder the options when the preferred payment method changes while the button is still visible // eslint-disable-next-line react-hooks/exhaustive-deps - }, [currency, formattedAmount, iouReport, policyID, translate, shouldHidePaymentOptions, shouldShowApproveButton, shouldDisableApproveButton]); + }, [currency, formattedAmount, iouReport, chatReport, policyID, translate, shouldHidePaymentOptions, shouldShowApproveButton, shouldDisableApproveButton]); const selectPaymentType = (event: KYCFlowEvent, iouPaymentType: PaymentMethodType, triggerKYCFlow: TriggerKYCFlow) => { if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA) { From d295bbf4af9ace96eb15577494a1389a1df092e0 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 27 Jun 2024 08:56:01 +0200 Subject: [PATCH 10/14] Align secondary avatar display with the main branch --- src/libs/ReportUtils.ts | 43 +------------------ .../home/report/ReportActionItemSingle.tsx | 39 ++++++++++++++--- 2 files changed, 34 insertions(+), 48 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 41c777d4fd0..95667d738d8 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1859,46 +1859,6 @@ function getDisplayNameForParticipant(accountID?: number, shouldUseShortForm = f return shouldUseShortForm ? shortName : longName; } -function getSecondaryAvatar(chatReport: OnyxEntry, iouReport: OnyxEntry, displayAllActors: boolean, isWorkspaceActor: boolean, actorAccountID?: number): Icon { - let secondaryAvatar: Icon; - - if (displayAllActors) { - if (isInvoiceRoom(chatReport) && !isIndividualInvoiceRoom(chatReport)) { - const secondaryPolicyID = chatReport?.invoiceReceiver && 'policyID' in chatReport.invoiceReceiver ? chatReport.invoiceReceiver.policyID : '-1'; - const secondaryPolicy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${secondaryPolicyID}`]; - const secondaryPolicyAvatar = secondaryPolicy?.avatarURL ?? getDefaultWorkspaceAvatar(secondaryPolicy?.name); - - secondaryAvatar = { - source: secondaryPolicyAvatar, - type: CONST.ICON_TYPE_WORKSPACE, - name: secondaryPolicy?.name, - id: secondaryPolicyID, - }; - } else { - // The ownerAccountID and actorAccountID can be the same if the user submits an expense back from the IOU's original creator, in that case we need to use managerID to avoid displaying the same user twice - const secondaryAccountId = iouReport?.ownerAccountID === actorAccountID || isInvoiceReport(iouReport) ? iouReport?.managerID : iouReport?.ownerAccountID; - const secondaryUserAvatar = allPersonalDetails?.[secondaryAccountId ?? -1]?.avatar ?? FallbackAvatar; - const secondaryDisplayName = getDisplayNameForParticipant(secondaryAccountId); - - secondaryAvatar = { - source: secondaryUserAvatar, - type: CONST.ICON_TYPE_AVATAR, - name: secondaryDisplayName ?? '', - id: secondaryAccountId, - }; - } - } else if (!isWorkspaceActor) { - const avatarIconIndex = !!chatReport?.isOwnPolicyExpenseChat || isPolicyExpenseChat(chatReport) ? 0 : 1; - const reportIcons = getIcons(chatReport, {}); - - secondaryAvatar = reportIcons[avatarIconIndex]; - } else { - secondaryAvatar = {name: '', source: '', type: 'avatar'}; - } - - return secondaryAvatar; -} - function getParticipantsAccountIDsForDisplay(report: OnyxEntry, shouldExcludeHidden = false, shouldExcludeDeleted = false): number[] { let participantsEntries = Object.entries(report?.participants ?? {}); @@ -2609,7 +2569,7 @@ function getMoneyRequestReportName(report: OnyxEntry, policy?: OnyxEntry if (isExpenseReport(report)) { payerOrApproverName = getPolicyName(report, false, policy); } else if (isInvoiceReport(report)) { - const chatReport = getReport(report?.chatReportID); + const chatReport = getReportOrDraftReport(report?.chatReportID); payerOrApproverName = getInvoicePayerName(chatReport); } else { payerOrApproverName = getDisplayNameForParticipant(report?.managerID) ?? ''; @@ -7379,7 +7339,6 @@ export { getChatUsedForOnboarding, findPolicyExpenseChatByPolicyID, isIndividualInvoiceRoom, - getSecondaryAvatar, }; export type { diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 75c864fa467..53527e85b21 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -19,11 +19,13 @@ import useThemeStyles from '@hooks/useThemeStyles'; import ControlSelection from '@libs/ControlSelection'; import DateUtils from '@libs/DateUtils'; import Navigation from '@libs/Navigation/Navigation'; +import * as PolicyUtils from '@libs/PolicyUtils'; import {getReportActionMessage} from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type {Report, ReportAction} from '@src/types/onyx'; +import type {Icon} from '@src/types/onyx/OnyxCommon'; import type ChildrenProps from '@src/types/utils/ChildrenProps'; import ReportActionItemDate from './ReportActionItemDate'; import ReportActionItemFragment from './ReportActionItemFragment'; @@ -108,16 +110,41 @@ function ReportActionItemSingle({ } // If this is a report preview, display names and avatars of both people involved - const secondaryAvatar = ReportUtils.getSecondaryAvatar(report, iouReport, displayAllActors, isWorkspaceActor, actorAccountID); + let secondaryAvatar: Icon; const primaryDisplayName = displayName; if (displayAllActors) { - // The ownerAccountID and actorAccountID can be the same if a user submits an expense back from the IOU's original creator, in that case we need to use managerID to avoid displaying the same user twice - const secondaryAccountId = ownerAccountID === actorAccountID || isInvoiceReport ? actorAccountID : ownerAccountID; - const secondaryDisplayName = ReportUtils.getDisplayNameForParticipant(secondaryAccountId); + if (ReportUtils.isInvoiceRoom(report) && !ReportUtils.isIndividualInvoiceRoom(report)) { + const secondaryPolicyID = report?.invoiceReceiver && 'policyID' in report.invoiceReceiver ? report.invoiceReceiver.policyID : '-1'; + const secondaryPolicy = PolicyUtils.getPolicy(secondaryPolicyID); + const secondaryPolicyAvatar = secondaryPolicy?.avatarURL ?? ReportUtils.getDefaultWorkspaceAvatar(secondaryPolicy?.name); - if (!isInvoiceReport) { - displayName = `${primaryDisplayName} & ${secondaryDisplayName}`; + secondaryAvatar = { + source: secondaryPolicyAvatar, + type: CONST.ICON_TYPE_WORKSPACE, + name: secondaryPolicy?.name, + id: secondaryPolicyID, + }; + } else { + // The ownerAccountID and actorAccountID can be the same if a user submits an expense back from the IOU's original creator, in that case we need to use managerID to avoid displaying the same user twice + const secondaryAccountId = ownerAccountID === actorAccountID || isInvoiceReport ? actorAccountID : ownerAccountID; + const secondaryUserAvatar = personalDetails?.[secondaryAccountId ?? -1]?.avatar ?? FallbackAvatar; + const secondaryDisplayName = ReportUtils.getDisplayNameForParticipant(secondaryAccountId); + + secondaryAvatar = { + source: secondaryUserAvatar, + type: CONST.ICON_TYPE_AVATAR, + name: secondaryDisplayName ?? '', + id: secondaryAccountId, + }; } + } else if (!isWorkspaceActor) { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const avatarIconIndex = report.isOwnPolicyExpenseChat || ReportUtils.isPolicyExpenseChat(report) ? 0 : 1; + const reportIcons = ReportUtils.getIcons(report, {}); + + secondaryAvatar = reportIcons[avatarIconIndex]; + } else { + secondaryAvatar = {name: '', source: '', type: 'avatar'}; } const icon = { source: avatarSource ?? FallbackAvatar, From f3fe9a88e1e7995b00d05ec73c736af29d7b0379 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 27 Jun 2024 09:41:14 +0200 Subject: [PATCH 11/14] Move the b2c invoice to an existing b2b room --- src/libs/actions/IOU.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index f68c7805bb6..3b2e7603591 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -5927,7 +5927,7 @@ function getSendMoneyParams( } function getPayMoneyRequestParams( - chatReport: OnyxTypes.Report, + initialChatReport: OnyxTypes.Report, iouReport: OnyxTypes.Report, recipient: Participant, paymentMethodType: PaymentMethodType, @@ -5935,6 +5935,14 @@ function getPayMoneyRequestParams( payAsBusiness?: boolean, ): PayMoneyRequestData { const isInvoiceReport = ReportUtils.isInvoiceReport(iouReport); + let chatReport = initialChatReport; + + if (ReportUtils.isIndividualInvoiceRoom(chatReport) && payAsBusiness && primaryPolicyID) { + const existingB2BInvoiceRoom = ReportUtils.getInvoiceChatByParticipants(chatReport.policyID ?? '', primaryPolicyID); + if (existingB2BInvoiceRoom) { + chatReport = existingB2BInvoiceRoom; + } + } let total = (iouReport.total ?? 0) - (iouReport.nonReimbursableTotal ?? 0); if (ReportUtils.hasHeldExpenses(iouReport.reportID) && !full && !!iouReport.unheldTotal) { From 73016466eb37336e3da7ec8762766529440f8eeb Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 27 Jun 2024 09:48:47 +0200 Subject: [PATCH 12/14] Fix expense created in a wrong chat --- src/libs/ReportUtils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 95667d738d8..2bcdd4b0f6c 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -5563,6 +5563,7 @@ function getChatByParticipants(newParticipantList: number[], reports: OnyxCollec isChatThread(report) || isTaskReport(report) || isMoneyRequestReport(report) || + isInvoiceReport(report) || isChatRoom(report) || isPolicyExpenseChat(report) || (isGroupChat(report) && !shouldIncludeGroupChats) From 968373e9097e2c0adf24bea7f79b8489a7b502b0 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Thu, 27 Jun 2024 10:00:12 +0200 Subject: [PATCH 13/14] Minor code improvement --- src/components/SettlementButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 7367b009a74..12dad8e82a2 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -145,7 +145,7 @@ function SettlementButton({ const {isOffline} = useNetwork(); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); - const primaryPolicy = useMemo(() => PolicyActions.getPrimaryPolicy(activePolicyID) ?? null, [activePolicyID]); + const primaryPolicy = useMemo(() => PolicyActions.getPrimaryPolicy(activePolicyID), [activePolicyID]); const session = useSession(); // The app would crash due to subscribing to the entire report collection if chatReportID is an empty string. So we should have a fallback ID here. From f780f3d17f65a259cdfadf89f6c5f978f31a050f Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 28 Jun 2024 16:31:21 +0200 Subject: [PATCH 14/14] Update the check --- src/components/SettlementButton.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 12dad8e82a2..8c6d98ecd1b 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -219,7 +219,7 @@ function SettlementButton({ }); } - if (PolicyUtils.isPolicyAdmin(primaryPolicy)) { + if (PolicyUtils.isPolicyAdmin(primaryPolicy) && PolicyUtils.isPaidGroupPolicy(primaryPolicy)) { buttonOptions.push({ text: translate('iou.settleBusiness', {formattedAmount}), icon: Expensicons.Building, @@ -248,7 +248,7 @@ function SettlementButton({ return buttonOptions; // We don't want to reorder the options when the preferred payment method changes while the button is still visible // eslint-disable-next-line react-hooks/exhaustive-deps - }, [currency, formattedAmount, iouReport, chatReport, policyID, translate, shouldHidePaymentOptions, shouldShowApproveButton, shouldDisableApproveButton]); + }, [currency, formattedAmount, iouReport, chatReport, policyID, translate, shouldHidePaymentOptions, primaryPolicy, shouldShowApproveButton, shouldDisableApproveButton]); const selectPaymentType = (event: KYCFlowEvent, iouPaymentType: PaymentMethodType, triggerKYCFlow: TriggerKYCFlow) => { if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA) {