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 ec52a6158ad7..43b2ca6729ea 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 4677563d204f..abdb963530de 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 b6e2a753c829..c5eaa0dec336 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 4c6633749adb..a6b9746d87bc 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 7e99c60cb618..7f06ebad8601 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 a98a9c315173..6e8d065fb625 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 4d918352ba91..f3d152d81c40 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 abdb963530de..36831e26291e 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 7f06ebad8601..b2a18925c9b4 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 f71db06c2d44..e6a870879598 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 c5eaa0dec336..62b0c2ee89ac 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 b2a18925c9b4..68f1cf9c830a 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 e6a870879598..eee4f570ef1f 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 68f1cf9c830a..2569bc56a331 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 62b0c2ee89ac..d06d514d5657 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 71148ce876e0..5cfa2a165fd1 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 0e88abd18860..275184d6d5a2 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 d53f0ba2186d..8681f52d2538 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 8681f52d2538..3ae370112a0c 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 b537d43e3df3..51d1df35f9ac 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 1683ef3e3df2..55cd658b4afd 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 b1386e1a6fa3..de1197c78f32 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 41c777d4fd0d..95667d738d8d 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 75c864fa4675..53527e85b215 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 f68c7805bb66..3b2e76035915 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 95667d738d8d..2bcdd4b0f6c3 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 7367b009a745..12dad8e82a28 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 12dad8e82a28..8c6d98ecd1bc 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) {