From 665b508f285e3b6390bcbaa6e889bc3ed115cfba Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Wed, 8 May 2024 20:39:56 +0200 Subject: [PATCH 01/20] updated settlement button, added invoice payment --- assets/images/checkmark-circle.svg | 3 ++ src/CONST.ts | 2 + src/components/Icon/Expensicons.ts | 2 + src/components/MoneyReportHeader.tsx | 10 +++-- .../ReportActionItem/ReportPreview.tsx | 21 +++++++-- src/components/SettlementButton.tsx | 18 +++++++- src/languages/en.ts | 10 +++++ src/languages/es.ts | 10 +++++ src/libs/API/parameters/PayInvoiceParams.ts | 9 ++++ src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 + src/libs/ReportUtils.ts | 2 +- src/libs/actions/IOU.ts | 44 +++++++++++++++++-- 13 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 assets/images/checkmark-circle.svg create mode 100644 src/libs/API/parameters/PayInvoiceParams.ts diff --git a/assets/images/checkmark-circle.svg b/assets/images/checkmark-circle.svg new file mode 100644 index 000000000000..3497548bc1bc --- /dev/null +++ b/assets/images/checkmark-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/CONST.ts b/src/CONST.ts index 19720c05a93c..aa26aaedf3e0 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1511,6 +1511,8 @@ const CONST = { ELSEWHERE: 'Elsewhere', EXPENSIFY: 'Expensify', VBBA: 'ACH', + PERSONAL: 'PERSONAL', + BUSINESS: 'BUSINESS', }, ACTION: { EDIT: 'edit', diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts index 74dbf8622a24..d55e00906654 100644 --- a/src/components/Icon/Expensicons.ts +++ b/src/components/Icon/Expensicons.ts @@ -35,6 +35,7 @@ import ChatBubbleReply from '@assets/images/chatbubble-reply.svg'; import ChatBubbleUnread from '@assets/images/chatbubble-unread.svg'; import ChatBubble from '@assets/images/chatbubble.svg'; import ChatBubbles from '@assets/images/chatbubbles.svg'; +import CheckmarkCircle from '@assets/images/checkmark-circle.svg'; import Checkmark from '@assets/images/checkmark.svg'; import Close from '@assets/images/close.svg'; import ClosedSign from '@assets/images/closed-sign.svg'; @@ -336,4 +337,5 @@ export { Lightbulb, DocumentPlus, Clear, + CheckmarkCircle, }; diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index e1a998f78cab..6ce6b868a376 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -112,7 +112,7 @@ function MoneyReportHeader({ const shouldDisableApproveButton = shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(moneyRequestReport); - const shouldShowSettlementButton = !ReportUtils.isInvoiceReport(moneyRequestReport) && (shouldShowPayButton || shouldShowApproveButton); + const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; const shouldShowSubmitButton = isDraft && reimbursableSpend !== 0; const shouldDisableSubmitButton = shouldShowSubmitButton && !ReportUtils.isAllowedToSubmitDraftExpenseReport(moneyRequestReport); @@ -126,14 +126,16 @@ function MoneyReportHeader({ const isMoreContentShown = shouldShowNextStep || (shouldShowAnyButton && shouldUseNarrowLayout); const confirmPayment = (type?: PaymentMethodType | undefined) => { - if (!type) { + if (!type || !chatReport) { return; } setPaymentType(type); setRequestType('pay'); if (ReportUtils.hasHeldExpenses(moneyRequestReport.reportID)) { setIsHoldMenuVisible(true); - } else if (chatReport) { + } else if (ReportUtils.isInvoiceReport(moneyRequestReport)) { + IOU.payInvoice(type, chatReport, moneyRequestReport); + } else { IOU.payMoneyRequest(type, chatReport, moneyRequestReport, true); } }; @@ -217,6 +219,7 @@ function MoneyReportHeader({ chatReportID={chatReport?.reportID} iouReport={moneyRequestReport} onPress={confirmPayment} + invoicePaymentMethod={paymentType} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} shouldHidePaymentOptions={!shouldShowPayButton} @@ -251,6 +254,7 @@ function MoneyReportHeader({ chatReportID={moneyRequestReport.chatReportID} iouReport={moneyRequestReport} onPress={confirmPayment} + invoicePaymentMethod={paymentType} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} shouldHidePaymentOptions={!shouldShowPayButton} diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 54f9f1aa081f..3b10ec1967aa 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -1,4 +1,5 @@ -import React, {useMemo} from 'react'; +import ExpensiMark from 'expensify-common/lib/ExpensiMark'; +import React, {useMemo, useState} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; @@ -103,6 +104,7 @@ function ReportPreview({ const styles = useThemeStyles(); const {translate} = useLocalize(); const {canUseViolations} = usePermissions(); + const [paymentType, setPaymentType] = useState(); const {hasMissingSmartscanFields, areAllRequestsBeingSmartScanned, hasOnlyTransactionsWithPendingRoutes, hasNonReimbursableTransactions} = useMemo( () => ({ @@ -208,7 +210,7 @@ function ReportPreview({ const shouldDisableApproveButton = shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport); - const shouldShowSettlementButton = !ReportUtils.isInvoiceReport(iouReport) && (shouldShowPayButton || shouldShowApproveButton); + const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; const shouldPromptUserToAddBankAccount = ReportUtils.hasMissingPaymentMethod(userWallet, iouReportID); const shouldShowRBR = !iouSettled && hasErrors; @@ -241,6 +243,18 @@ function ReportPreview({ }; }, [formattedMerchant, formattedDescription, moneyRequestComment, translate, numberOfRequests, numberOfScanningReceipts, numberOfPendingRequests]); + const confirmPayment = (paymentMethodType?: PaymentMethodType) => { + if (!paymentMethodType || !chatReport || !iouReport) { + return; + } + setPaymentType(paymentMethodType); + if (ReportUtils.isInvoiceReport(iouReport)) { + IOU.payInvoice(paymentMethodType, chatReport, iouReport); + } else { + IOU.payMoneyRequest(paymentMethodType, chatReport, iouReport); + } + }; + return ( chatReport && iouReport && paymentType && IOU.payMoneyRequest(paymentType, chatReport, iouReport)} + onPress={confirmPayment} + invoicePaymentMethod={paymentType} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} shouldHidePaymentOptions={!shouldShowPayButton} diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index f56c4dd1a863..227457f795d0 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -17,7 +17,7 @@ import type {ButtonSizeValue} from '@src/styles/utils/types'; import type {LastPaymentMethod, Policy, Report} from '@src/types/onyx'; import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; -import type {EmptyObject} from '@src/types/utils/EmptyObject'; +import {type EmptyObject, isEmptyObject} from '@src/types/utils/EmptyObject'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import type {PaymentType} from './ButtonWithDropdownMenu/types'; import * as Expensicons from './Icon/Expensicons'; @@ -104,6 +104,9 @@ type SettlementButtonProps = SettlementButtonOnyxProps & { /** Callback to open confirmation modal if any of the transactions is on HOLD */ confirmApproval?: () => void; + + /** personal/business methods which should be displayed */ + invoicePaymentMethod?: typeof CONST.IOU.PAYMENT_TYPE.PERSONAL | typeof CONST.IOU.PAYMENT_TYPE.BUSINESS; }; function SettlementButton({ @@ -139,6 +142,7 @@ function SettlementButton({ enterKeyEventListenerPriority = 0, confirmApproval, policy, + invoicePaymentMethod, }: SettlementButtonProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); @@ -155,6 +159,7 @@ function SettlementButton({ const paymentButtonOptions = useMemo(() => { const buttonOptions = []; const isExpenseReport = ReportUtils.isExpenseReport(iouReport); + const isInvoiceRoom = (!isEmptyObject(iouReport) && ReportUtils.isInvoiceReport(iouReport)) || false; const paymentMethods = { [CONST.IOU.PAYMENT_TYPE.EXPENSIFY]: { text: translate('iou.settleExpensify', {formattedAmount}), @@ -171,6 +176,11 @@ function SettlementButton({ icon: Expensicons.Cash, value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, }, + [CONST.IOU.PAYMENT_TYPE.PERSONAL]: { + text: translate('iou.settlePersonal', {formattedAmount}), + icon: Expensicons.User, + value: CONST.IOU.PAYMENT_TYPE.PERSONAL, + }, }; const approveButtonOption = { text: translate('iou.approve'), @@ -195,9 +205,12 @@ function SettlementButton({ if (isExpenseReport && shouldShowPaywithExpensifyOption) { buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.VBBA]); } - if (shouldShowPayElsewhereOption) { + if (shouldShowPayElsewhereOption || (isInvoiceRoom && invoicePaymentMethod)) { buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.ELSEWHERE]); } + if (isInvoiceRoom && !invoicePaymentMethod) { + buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.PERSONAL]); + } if (shouldShowApproveButton) { buttonOptions.push(approveButtonOption); @@ -211,6 +224,7 @@ function SettlementButton({ // 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]); + const selectPaymentType = (event: KYCFlowEvent, iouPaymentType: PaymentMethodType, triggerKYCFlow: TriggerKYCFlow) => { if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA) { triggerKYCFlow(event, iouPaymentType); diff --git a/src/languages/en.ts b/src/languages/en.ts index b5902b243d38..1b357a4d5b3d 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -665,6 +665,8 @@ export default { settledExpensify: 'Paid', settledElsewhere: 'Paid elsewhere', settleExpensify: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} with Expensify` : `Pay with Expensify`), + settlePersonal: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} as an individual` : `Pay as an individual`), + settleBusiness: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} as a business` : `Pay as a business`), payElsewhere: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} elsewhere` : `Pay elsewhere`), nextStep: 'Next Steps', finished: 'Finished', @@ -2379,6 +2381,14 @@ export default { viewUnpaidInvoices: 'View unpaid invoices', sendInvoice: 'Send invoice', sendFrom: 'Send from', + paymentMethods: { + personal: 'Personal', + business: 'Business', + chooseInvoiceMethod: 'Choose a payment method below:', + addBankAccount: 'Add bank account', + payingAsIndividual: 'Paying as an individual', + payingAsBusiness: 'Paying as a business', + }, }, travel: { unlockConciergeBookingTravel: 'Unlock Concierge travel booking', diff --git a/src/languages/es.ts b/src/languages/es.ts index d71a95329928..cb354f46dddb 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -659,6 +659,8 @@ export default { settledElsewhere: 'Pagado de otra forma', settleExpensify: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pagar ${formattedAmount} con Expensify` : `Pagar con Expensify`), payElsewhere: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pagar ${formattedAmount} de otra forma` : `Pagar de otra forma`), + settlePersonal: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} as an individual` : `Pay as an individual`), + settleBusiness: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} as a business` : `Pay as a business`), nextStep: 'Pasos Siguientes', finished: 'Finalizado', sendInvoice: ({amount}: RequestAmountParams) => `Enviar factura de ${amount}`, @@ -2415,6 +2417,14 @@ export default { viewUnpaidInvoices: 'Ver facturas emitidas pendientes', sendInvoice: 'Enviar factura', sendFrom: 'Enviar desde', + paymentMethods: { + personal: 'Personal', + business: 'Business', + chooseInvoiceMethod: 'Choose a payment method below:', + addBankAccount: 'Add bank account', + payingAsIndividual: 'Paying as an individual', + payingAsBusiness: 'Paying as a business', + }, }, travel: { unlockConciergeBookingTravel: 'Desbloquea la reserva de viajes con Concierge', diff --git a/src/libs/API/parameters/PayInvoiceParams.ts b/src/libs/API/parameters/PayInvoiceParams.ts new file mode 100644 index 000000000000..4c6633749adb --- /dev/null +++ b/src/libs/API/parameters/PayInvoiceParams.ts @@ -0,0 +1,9 @@ +import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; + +type PayInvoiceParams = { + reportID: string; + reportActionID: string; + paymentMethodType: PaymentMethodType; +}; + +export default PayInvoiceParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index a142d5324aa4..c90820e09cea 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -220,3 +220,4 @@ export type {default as LeavePolicyParams} from './LeavePolicyParams'; export type {default as OpenPolicyAccountingPageParams} from './OpenPolicyAccountingPageParams'; export type {default as SearchParams} from './Search'; export type {default as SendInvoiceParams} from './SendInvoiceParams'; +export type {default as PayInvoiceParams} from './PayInvoiceParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index ba06ec1d6429..907a5d4e2e98 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -216,6 +216,7 @@ const WRITE_COMMANDS = { LEAVE_POLICY: 'LeavePolicy', ACCEPT_SPOTNANA_TERMS: 'AcceptSpotnanaTerms', SEND_INVOICE: 'SendInvoice', + PAY_INVOICE: 'PayInvoice', } as const; type WriteCommand = ValueOf; @@ -432,6 +433,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.LEAVE_POLICY]: Parameters.LeavePolicyParams; [WRITE_COMMANDS.ACCEPT_SPOTNANA_TERMS]: EmptyObject; [WRITE_COMMANDS.SEND_INVOICE]: Parameters.SendInvoiceParams; + [WRITE_COMMANDS.PAY_INVOICE]: Parameters.PayInvoiceParams; }; const READ_COMMANDS = { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index fb3371e94491..6d67da918c9e 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -900,7 +900,7 @@ function isPolicyExpenseChat(report: OnyxEntry | Participant | EmptyObje return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT || (report?.isPolicyExpenseChat ?? false); } -function isInvoiceRoom(report: OnyxEntry): boolean { +function isInvoiceRoom(report: OnyxEntry | EmptyObject): boolean { return getChatType(report) === CONST.REPORT.CHAT_TYPE.INVOICE; } diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 79ee20971e5d..bc311fdcdb62 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -14,6 +14,7 @@ import type { DeleteMoneyRequestParams, DetachReceiptParams, EditMoneyRequestParams, + PayInvoiceParams, PayMoneyRequestParams, ReplaceReceiptParams, RequestMoneyParams, @@ -214,6 +215,15 @@ Onyx.connect({ }, }); +let activePolicyID = ''; +Onyx.connect({ + key: ONYXKEYS.NVP_ACTIVE_POLICY_ID, + waitForCollectionCallback: true, + callback: (value) => { + activePolicyID = value ?? ''; + }, +}); + let allNextSteps: NonNullable> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.NEXT_STEP, @@ -5651,6 +5661,8 @@ function getPayMoneyRequestParams( paymentMethodType: PaymentMethodType, full: boolean, ): PayMoneyRequestData { + const isInvoiceReport = ReportUtils.isInvoiceReport(iouReport); + let total = (iouReport.total ?? 0) - (iouReport.nonReimbursableTotal ?? 0); if (ReportUtils.hasHeldExpenses(iouReport.reportID) && !full && !!iouReport.unheldTotal) { total = iouReport.unheldTotal; @@ -5675,9 +5687,12 @@ function getPayMoneyRequestParams( if (reportPreviewAction) { optimisticReportPreviewAction = ReportUtils.updateReportPreview(iouReport, reportPreviewAction, true); } - - const currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport.reportID}`] ?? null; - const optimisticNextStep = NextStepUtils.buildNextStep(iouReport, CONST.REPORT.STATUS_NUM.REIMBURSED, {isPaidWithExpensify: paymentMethodType === CONST.IOU.PAYMENT_TYPE.VBBA}); + let currentNextStep = null; + let optimisticNextStep = null; + if (!isInvoiceReport) { + currentNextStep = allNextSteps[`${ONYXKEYS.COLLECTION.NEXT_STEP}${iouReport.reportID}`]; + optimisticNextStep = NextStepUtils.buildNextStep(iouReport, CONST.REPORT.STATUS_NUM.REIMBURSED, {isPaidWithExpensify: paymentMethodType === CONST.IOU.PAYMENT_TYPE.VBBA}); + } const optimisticData: OnyxUpdate[] = [ { @@ -5874,6 +5889,10 @@ function canIOUBePaid(iouReport: OnyxEntry | EmptyObject, chat return false; } + if (ReportUtils.isInvoiceRoom(iouReport) && iouReport?.managerID === userAccountID) { + return true; + } + if (ReportUtils.isInvoiceReport(iouReport)) { if (chatReport?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL) { return chatReport?.invoiceReceiver?.accountID === userAccountID; @@ -6286,6 +6305,24 @@ function payMoneyRequest(paymentType: PaymentMethodType, chatReport: OnyxTypes.R Navigation.dismissModalWithReport(chatReport); } +function payInvoice(paymentMethodType: PaymentMethodType, chatReport: OnyxTypes.Report, invoiceReport: OnyxTypes.Report) { + const recipient = {accountID: invoiceReport.ownerAccountID}; + const { + optimisticData, + successData, + failureData, + params: {reportActionID}, + } = getPayMoneyRequestParams(chatReport, invoiceReport, recipient, paymentMethodType, true); + + const params: PayInvoiceParams = { + reportID: chatReport.reportID, + reportActionID, + paymentMethodType, + }; + + API.write(WRITE_COMMANDS.PAY_INVOICE, params, {optimisticData, successData, failureData}); +} + function detachReceipt(transactionID: string) { const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const newTransaction = transaction ? {...transaction, filename: '', receipt: {}} : null; @@ -6673,6 +6710,7 @@ export { initMoneyRequest, navigateToStartStepIfScanFileCannotBeRead, payMoneyRequest, + payInvoice, putOnHold, replaceReceipt, requestMoney, From 22edb598136ade4a4881d2e771f16f9e1c8452c2 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Wed, 8 May 2024 20:45:28 +0200 Subject: [PATCH 02/20] remove unused activeUserID --- src/libs/actions/IOU.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index bc311fdcdb62..83a5f247795b 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -215,15 +215,6 @@ Onyx.connect({ }, }); -let activePolicyID = ''; -Onyx.connect({ - key: ONYXKEYS.NVP_ACTIVE_POLICY_ID, - waitForCollectionCallback: true, - callback: (value) => { - activePolicyID = value ?? ''; - }, -}); - let allNextSteps: NonNullable> = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.NEXT_STEP, From 5e56c7f5a5b2d9d9f98a305043d838b77cd08d43 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Thu, 9 May 2024 20:23:35 +0200 Subject: [PATCH 03/20] fixed payments and ts issues --- src/components/MoneyReportHeader.tsx | 2 -- .../ReportActionItem/ReportPreview.tsx | 4 ---- src/components/SettlementButton.tsx | 16 +++++++--------- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index 6ce6b868a376..68b6b2ad2720 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -219,7 +219,6 @@ function MoneyReportHeader({ chatReportID={chatReport?.reportID} iouReport={moneyRequestReport} onPress={confirmPayment} - invoicePaymentMethod={paymentType} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} shouldHidePaymentOptions={!shouldShowPayButton} @@ -254,7 +253,6 @@ function MoneyReportHeader({ chatReportID={moneyRequestReport.chatReportID} iouReport={moneyRequestReport} onPress={confirmPayment} - invoicePaymentMethod={paymentType} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} shouldHidePaymentOptions={!shouldShowPayButton} diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 3b10ec1967aa..77d00eb97708 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -1,4 +1,3 @@ -import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import React, {useMemo, useState} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; @@ -104,7 +103,6 @@ function ReportPreview({ const styles = useThemeStyles(); const {translate} = useLocalize(); const {canUseViolations} = usePermissions(); - const [paymentType, setPaymentType] = useState(); const {hasMissingSmartscanFields, areAllRequestsBeingSmartScanned, hasOnlyTransactionsWithPendingRoutes, hasNonReimbursableTransactions} = useMemo( () => ({ @@ -247,7 +245,6 @@ function ReportPreview({ if (!paymentMethodType || !chatReport || !iouReport) { return; } - setPaymentType(paymentMethodType); if (ReportUtils.isInvoiceReport(iouReport)) { IOU.payInvoice(paymentMethodType, chatReport, iouReport); } else { @@ -333,7 +330,6 @@ function ReportPreview({ chatReportID={chatReportID} iouReport={iouReport} onPress={confirmPayment} - invoicePaymentMethod={paymentType} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} shouldHidePaymentOptions={!shouldShowPayButton} diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 227457f795d0..b0769998d29e 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -17,7 +17,8 @@ import type {ButtonSizeValue} from '@src/styles/utils/types'; import type {LastPaymentMethod, Policy, Report} from '@src/types/onyx'; import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage'; import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; -import {type EmptyObject, isEmptyObject} from '@src/types/utils/EmptyObject'; +import type {EmptyObject} from '@src/types/utils/EmptyObject'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import type {PaymentType} from './ButtonWithDropdownMenu/types'; import * as Expensicons from './Icon/Expensicons'; @@ -104,9 +105,6 @@ type SettlementButtonProps = SettlementButtonOnyxProps & { /** Callback to open confirmation modal if any of the transactions is on HOLD */ confirmApproval?: () => void; - - /** personal/business methods which should be displayed */ - invoicePaymentMethod?: typeof CONST.IOU.PAYMENT_TYPE.PERSONAL | typeof CONST.IOU.PAYMENT_TYPE.BUSINESS; }; function SettlementButton({ @@ -142,7 +140,6 @@ function SettlementButton({ enterKeyEventListenerPriority = 0, confirmApproval, policy, - invoicePaymentMethod, }: SettlementButtonProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); @@ -153,13 +150,13 @@ function SettlementButton({ const session = useSession(); const chatReport = ReportUtils.getReport(chatReportID); + const isInvoiceReport = (!isEmptyObject(iouReport) && ReportUtils.isInvoiceReport(iouReport)) || false; const isPaidGroupPolicy = ReportUtils.isPaidGroupPolicyExpenseChat(chatReport); const shouldShowPaywithExpensifyOption = !isPaidGroupPolicy || (!shouldHidePaymentOptions && ReportUtils.isPayer(session, iouReport as OnyxEntry)); - const shouldShowPayElsewhereOption = !isPaidGroupPolicy || policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_MANUAL; + const shouldShowPayElsewhereOption = (!isPaidGroupPolicy || policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_MANUAL) && !isInvoiceReport; const paymentButtonOptions = useMemo(() => { const buttonOptions = []; const isExpenseReport = ReportUtils.isExpenseReport(iouReport); - const isInvoiceRoom = (!isEmptyObject(iouReport) && ReportUtils.isInvoiceReport(iouReport)) || false; const paymentMethods = { [CONST.IOU.PAYMENT_TYPE.EXPENSIFY]: { text: translate('iou.settleExpensify', {formattedAmount}), @@ -205,10 +202,11 @@ function SettlementButton({ if (isExpenseReport && shouldShowPaywithExpensifyOption) { buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.VBBA]); } - if (shouldShowPayElsewhereOption || (isInvoiceRoom && invoicePaymentMethod)) { + if (shouldShowPayElsewhereOption) { buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.ELSEWHERE]); } - if (isInvoiceRoom && !invoicePaymentMethod) { + + if (isInvoiceReport) { buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.PERSONAL]); } From 1ea1fc35c7492d8640b6a84a658450c52699d94c Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Fri, 10 May 2024 12:03:49 +0200 Subject: [PATCH 04/20] remove unused canIOUbePaid part, remove unused useState --- src/components/ReportActionItem/ReportPreview.tsx | 2 +- src/libs/actions/IOU.ts | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index 77d00eb97708..5a0fe3e47998 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -1,4 +1,4 @@ -import React, {useMemo, useState} from 'react'; +import React, {useMemo} from 'react'; import type {StyleProp, ViewStyle} from 'react-native'; import {View} from 'react-native'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 83a5f247795b..c7093e43b6cc 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -5880,15 +5880,10 @@ function canIOUBePaid(iouReport: OnyxEntry | EmptyObject, chat return false; } - if (ReportUtils.isInvoiceRoom(iouReport) && iouReport?.managerID === userAccountID) { - return true; - } - if (ReportUtils.isInvoiceReport(iouReport)) { if (chatReport?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL) { return chatReport?.invoiceReceiver?.accountID === userAccountID; } - return PolicyUtils.getPolicy(chatReport?.invoiceReceiver?.policyID).role === CONST.POLICY.ROLE.ADMIN; } From 8afc6fce18443074aaaece16203f87983be54e87 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Fri, 10 May 2024 12:54:37 +0200 Subject: [PATCH 05/20] added translations --- src/languages/es.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index cb354f46dddb..a66f18d01178 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -2419,11 +2419,11 @@ export default { sendFrom: 'Enviar desde', paymentMethods: { personal: 'Personal', - business: 'Business', - chooseInvoiceMethod: 'Choose a payment method below:', - addBankAccount: 'Add bank account', - payingAsIndividual: 'Paying as an individual', - payingAsBusiness: 'Paying as a business', + business: 'Empresas', + chooseInvoiceMethod: 'Elija un método de pago:', + addBankAccount: 'Añadir cuenta bancaria', + payingAsIndividual: 'Pago individual', + payingAsBusiness: 'Pagar como una empresa', }, }, travel: { From faaa568e25a97e3635e2cb37447aed39cd9c6589 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 13 May 2024 15:44:33 +0200 Subject: [PATCH 06/20] update params in payInvoice --- src/libs/actions/IOU.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 8fc99abdb6ed..ac30ba739a1e 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -6352,7 +6352,7 @@ function payInvoice(paymentMethodType: PaymentMethodType, chatReport: OnyxTypes. } = getPayMoneyRequestParams(chatReport, invoiceReport, recipient, paymentMethodType, true); const params: PayInvoiceParams = { - reportID: chatReport.reportID, + reportID: invoiceReport.reportID, reportActionID, paymentMethodType, }; From 15056526d7424997c4f3671525138a4090b95b71 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Mon, 13 May 2024 16:24:23 +0200 Subject: [PATCH 07/20] remove PERSONAL & BUSINESS payment types --- src/CONST.ts | 2 -- src/components/SettlementButton.tsx | 11 +++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index c589c5e5ce61..8a380188d05e 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1522,8 +1522,6 @@ const CONST = { ELSEWHERE: 'Elsewhere', EXPENSIFY: 'Expensify', VBBA: 'ACH', - PERSONAL: 'PERSONAL', - BUSINESS: 'BUSINESS', }, ACTION: { EDIT: 'edit', diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index b0769998d29e..d6235a3a3e02 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -173,11 +173,6 @@ function SettlementButton({ icon: Expensicons.Cash, value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, }, - [CONST.IOU.PAYMENT_TYPE.PERSONAL]: { - text: translate('iou.settlePersonal', {formattedAmount}), - icon: Expensicons.User, - value: CONST.IOU.PAYMENT_TYPE.PERSONAL, - }, }; const approveButtonOption = { text: translate('iou.approve'), @@ -207,7 +202,11 @@ function SettlementButton({ } if (isInvoiceReport) { - buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.PERSONAL]); + buttonOptions.push({ + text: translate('iou.settlePersonal', {formattedAmount}), + icon: Expensicons.User, + value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + }); } if (shouldShowApproveButton) { From a52e68d59b50fc4a1fac753be0a21e10cc05b104 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 14 May 2024 12:33:32 +0200 Subject: [PATCH 08/20] update isSettled --- src/libs/actions/IOU.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index ac30ba739a1e..5840b6c37ce0 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -5922,6 +5922,7 @@ function canApproveIOU(iouReport: OnyxEntry | EmptyObject, cha function canIOUBePaid(iouReport: OnyxEntry | EmptyObject, chatReport: OnyxEntry | EmptyObject, policy: OnyxEntry | EmptyObject) { const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(chatReport); const iouCanceled = ReportUtils.isArchivedRoom(chatReport); + const iouSettled = ReportUtils.isSettled(iouReport?.reportID); if (isEmptyObject(iouReport)) { return false; @@ -5932,6 +5933,9 @@ function canIOUBePaid(iouReport: OnyxEntry | EmptyObject, chat } if (ReportUtils.isInvoiceReport(iouReport)) { + if (iouSettled) { + return false; + } if (chatReport?.invoiceReceiver?.type === CONST.REPORT.INVOICE_RECEIVER_TYPE.INDIVIDUAL) { return chatReport?.invoiceReceiver?.accountID === userAccountID; } @@ -5947,7 +5951,6 @@ function canIOUBePaid(iouReport: OnyxEntry | EmptyObject, chat ); const isOpenExpenseReport = isPolicyExpenseChat && ReportUtils.isOpenExpenseReport(iouReport); - const iouSettled = ReportUtils.isSettled(iouReport?.reportID); const {reimbursableSpend} = ReportUtils.getMoneyRequestSpendBreakdown(iouReport); const isAutoReimbursable = policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_YES ? false : ReportUtils.canBeAutoReimbursed(iouReport, policy); From 6c2b1a1db45bb90e147bed0953a7787d5f676eed Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Fri, 17 May 2024 12:51:28 +0200 Subject: [PATCH 09/20] new view of the settlement button --- src/components/SettlementButton.tsx | 25 +++++++++++++++++++++++++ src/languages/en.ts | 1 + src/languages/es.ts | 1 + 3 files changed, 27 insertions(+) diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index d6235a3a3e02..ee876dec6f6c 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -206,6 +206,27 @@ function SettlementButton({ text: translate('iou.settlePersonal', {formattedAmount}), icon: Expensicons.User, 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), + }, + ], + }); + buttonOptions.push({ + text: translate('iou.settleBusiness', {formattedAmount}), + icon: Expensicons.User, + 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), + }, + ], }); } @@ -263,6 +284,10 @@ function SettlementButton({ success buttonRef={buttonRef} + shouldAlwaysShowDropdownMenu={isInvoiceReport} + customText={isInvoiceReport ? translate('iou.settlePayment', {formattedAmount}) : undefined} + menuHeaderText={isInvoiceReport ? translate('workspace.invoices.paymentMethods.chooseInvoiceMethod') : undefined} + isSplitButton={!isInvoiceReport} isDisabled={isDisabled} isLoading={isLoading} onPress={(event, iouPaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)} diff --git a/src/languages/en.ts b/src/languages/en.ts index 241824954807..2246a8a9646a 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -673,6 +673,7 @@ export default { settledElsewhere: 'Paid elsewhere', 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}`, settleBusiness: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} as a business` : `Pay as a business`), payElsewhere: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} elsewhere` : `Pay elsewhere`), nextStep: 'Next Steps', diff --git a/src/languages/es.ts b/src/languages/es.ts index 67e009ebbdfc..bb612a75bed1 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -667,6 +667,7 @@ export default { settleExpensify: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pagar ${formattedAmount} con Expensify` : `Pagar con Expensify`), payElsewhere: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pagar ${formattedAmount} de otra forma` : `Pagar de otra forma`), settlePersonal: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} as an individual` : `Pay as an individual`), + settlePayment: ({formattedAmount}: SettleExpensifyCardParams) => `Pagar ${formattedAmount}`, settleBusiness: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} as a business` : `Pay as a business`), nextStep: 'Pasos Siguientes', finished: 'Finalizado', From 86f6fb28747f09cd49759742eae73c4d031efd95 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 21 May 2024 14:45:51 +0200 Subject: [PATCH 10/20] fix modal, show amount, update text --- src/components/ReportActionItem/ReportPreview.tsx | 1 + src/components/SettlementButton.tsx | 4 ++-- src/pages/home/report/ReportActionItem.tsx | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index a9e8fee27378..f58468b380c7 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -358,6 +358,7 @@ function ReportPreview({ {shouldShowSettlementButton && ( onPress(CONST.IOU.PAYMENT_TYPE.ELSEWHERE), @@ -221,7 +221,7 @@ function SettlementButton({ value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, subMenuItems: [ { - text: translate('iou.payElsewhere', {formattedAmount}), + text: translate('iou.payElsewhere', {formattedAmount: ''}), icon: Expensicons.Cash, value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, onSelected: () => onPress(CONST.IOU.PAYMENT_TYPE.ELSEWHERE), diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 95bc4f5231d2..9c3693a97d4d 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -90,6 +90,9 @@ const getDraftMessage = (drafts: OnyxCollection, }; type ReportActionItemOnyxProps = { + /** Get modal status */ + modal: OnyxEntry; + /** IOU report for this action, if any */ iouReport: OnyxEntry; @@ -1053,6 +1056,7 @@ export default withOnyx({ const prevParentReportAction = prevProps.parentReportAction; const nextParentReportAction = nextProps.parentReportAction; return ( + prevProps.modal?.willAlertModalBecomeVisible === nextProps.modal?.willAlertModalBecomeVisible && prevProps.displayAsGroup === nextProps.displayAsGroup && prevProps.isMostRecentIOUReportAction === nextProps.isMostRecentIOUReportAction && prevProps.shouldDisplayNewMarker === nextProps.shouldDisplayNewMarker && From 524d6403e2817ce15692d72458bab24759e93113 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 21 May 2024 14:59:14 +0200 Subject: [PATCH 11/20] update hover, remove business button --- src/components/PopoverMenu.tsx | 19 ++++++++++++++++++- src/components/SettlementButton.tsx | 13 ------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index 8cd5ef529894..f95f167e3886 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -1,3 +1,4 @@ +import lodashIsEqual from 'lodash/isEqual'; import type {RefObject} from 'react'; import React, {useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; @@ -229,5 +230,21 @@ function PopoverMenu({ PopoverMenu.displayName = 'PopoverMenu'; -export default React.memo(PopoverMenu); +export default React.memo( + PopoverMenu, + (prevProps, nextProps) => + !lodashIsEqual(prevProps.menuItems, nextProps.menuItems) && + prevProps.isVisible === nextProps.isVisible && + lodashIsEqual(prevProps.anchorPosition, nextProps.anchorPosition) && + prevProps.anchorRef === nextProps.anchorRef && + prevProps.headerText === nextProps.headerText && + prevProps.fromSidebarMediumScreen === nextProps.fromSidebarMediumScreen && + lodashIsEqual(prevProps.anchorAlignment, nextProps.anchorAlignment) && + prevProps.animationIn === nextProps.animationIn && + prevProps.animationOut === nextProps.animationOut && + prevProps.animationInTiming === nextProps.animationInTiming && + prevProps.disableAnimation === nextProps.disableAnimation && + prevProps.withoutOverlay === nextProps.withoutOverlay && + prevProps.shouldSetModalVisibility === nextProps.shouldSetModalVisibility, +); export type {PopoverMenuItem, PopoverMenuProps}; diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index ac7c018d5c34..d1b5036eb970 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -215,19 +215,6 @@ function SettlementButton({ }, ], }); - buttonOptions.push({ - text: translate('iou.settleBusiness', {formattedAmount}), - icon: Expensicons.User, - 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), - }, - ], - }); } if (shouldShowApproveButton) { From e0ed7184fe30537005e3d1ab128ce002739a9645 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 21 May 2024 15:33:44 +0200 Subject: [PATCH 12/20] Revert "draft fix" This reverts commit ca45ed5791bcbcd3d11bdefefb73b9ed9d77c713. --- src/components/PopoverMenu.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index f95f167e3886..56f78f8e00b2 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -1,4 +1,3 @@ -import lodashIsEqual from 'lodash/isEqual'; import type {RefObject} from 'react'; import React, {useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; From 6da0e8ea54db7910dea30468f2ae3ea26f9ec895 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Tue, 21 May 2024 15:34:00 +0200 Subject: [PATCH 13/20] Revert "Revert "draft fix"" This reverts commit 9358ef70dc5447b6886735773cdacac826347724. --- src/components/PopoverMenu.tsx | 1 + src/pages/home/report/ReportActionItem.tsx | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index 56f78f8e00b2..f95f167e3886 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -1,3 +1,4 @@ +import lodashIsEqual from 'lodash/isEqual'; import type {RefObject} from 'react'; import React, {useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 9c3693a97d4d..35dcc642af37 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -167,6 +167,7 @@ const isIOUReport = (actionObj: OnyxEntry): actionObj is actionObj?.actionName === CONST.REPORT.ACTIONS.TYPE.IOU; function ReportActionItem({ + modal, action, report, transactionThreadReport, @@ -946,6 +947,7 @@ function ReportActionItem({ accessible > @@ -1051,6 +1053,9 @@ export default withOnyx({ key: ({action}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${(action as OnyxTypes.OriginalMessageIOU)?.originalMessage?.IOUTransactionID ?? 0}`, selector: (transaction: OnyxEntry) => transaction?.errorFields?.route ?? null, }, + modal: { + key: ONYXKEYS.MODAL, + }, })( memo(ReportActionItem, (prevProps, nextProps) => { const prevParentReportAction = prevProps.parentReportAction; @@ -1087,7 +1092,8 @@ export default withOnyx({ lodashIsEqual(prevProps.reportActions, nextProps.reportActions) && lodashIsEqual(prevProps.transaction, nextProps.transaction) && lodashIsEqual(prevProps.linkedTransactionRouteError, nextProps.linkedTransactionRouteError) && - lodashIsEqual(prevParentReportAction, nextParentReportAction) + lodashIsEqual(prevParentReportAction, nextParentReportAction) && + prevProps.modal?.willAlertModalBecomeVisible === nextProps.modal?.willAlertModalBecomeVisible ); }), ); From 7ca70bfa84cc815e555118f022f0bd15cb450c07 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Wed, 22 May 2024 17:08:38 +0200 Subject: [PATCH 14/20] update wallet for invoiceReport --- 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 d1b5036eb970..7ddbfa6e4928 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -180,7 +180,7 @@ function SettlementButton({ value: CONST.IOU.REPORT_ACTION_TYPE.APPROVE, disabled: !!shouldDisableApproveButton, }; - const canUseWallet = !isExpenseReport && currency === CONST.CURRENCY.USD; + const canUseWallet = !isExpenseReport && !isInvoiceReport && currency === CONST.CURRENCY.USD; // Only show the Approve button if the user cannot pay the expense if (shouldHidePaymentOptions && shouldShowApproveButton) { From 97a41aa954075bda1987471cb1b1f641e62f1f94 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Thu, 23 May 2024 14:01:08 +0200 Subject: [PATCH 15/20] stylings change --- src/components/PopoverMenu.tsx | 2 +- src/styles/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index f95f167e3886..09a5333d16ca 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -192,7 +192,7 @@ function PopoverMenu({ shouldSetModalVisibility={shouldSetModalVisibility} > - {!!headerText && {headerText}} + {!!headerText && enteredSubMenuIndexes.length === 0 && {headerText}} {enteredSubMenuIndexes.length > 0 && renderBackButtonItem()} {currentMenuItems.map((item, menuIndex) => ( createMenuHeaderText: { fontFamily: FontUtils.fontFamily.platform.EXP_NEUE, fontSize: variables.fontSizeLabel, - color: theme.heading, + color: theme.textSupporting, }, popoverMenuItem: { From cba930e71fa303588d6f698af91328d0f04f9abd Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Thu, 23 May 2024 16:00:20 +0200 Subject: [PATCH 16/20] updated stylings --- src/components/PopoverMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index 09a5333d16ca..1cdb09388a4a 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -192,7 +192,7 @@ function PopoverMenu({ shouldSetModalVisibility={shouldSetModalVisibility} > - {!!headerText && enteredSubMenuIndexes.length === 0 && {headerText}} + {!!headerText && enteredSubMenuIndexes.length === 0 && {headerText}} {enteredSubMenuIndexes.length > 0 && renderBackButtonItem()} {currentMenuItems.map((item, menuIndex) => ( Date: Fri, 24 May 2024 15:32:07 +0200 Subject: [PATCH 17/20] fixed focus --- src/components/PopoverMenu.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index 1cdb09388a4a..ae7aa14a7080 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -105,6 +105,7 @@ function PopoverMenu({ if (selectedItem?.subMenuItems) { setCurrentMenuItems([...selectedItem.subMenuItems]); setEnteredSubMenuIndexes([...enteredSubMenuIndexes, index]); + setFocusedIndex(-1); } else { selectedItemIndex.current = index; onItemSelected(selectedItem, index); @@ -137,6 +138,7 @@ function PopoverMenu({ description={previouslySelectedItem.description} onPress={() => { setCurrentMenuItems(previousMenuItems); + setFocusedIndex(-1); enteredSubMenuIndexes.splice(-1); }} /> From e5e73cc159abefbde23ecb9a448a8b8370ebb5e5 Mon Sep 17 00:00:00 2001 From: Artem Makushov Date: Fri, 24 May 2024 15:42:02 +0200 Subject: [PATCH 18/20] translations --- src/languages/es.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index bb612a75bed1..657c26a4458b 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -665,10 +665,10 @@ export default { settledExpensify: 'Pagado', settledElsewhere: 'Pagado de otra forma', settleExpensify: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pagar ${formattedAmount} con Expensify` : `Pagar con Expensify`), - payElsewhere: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pagar ${formattedAmount} de otra forma` : `Pagar de otra forma`), - settlePersonal: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} as an individual` : `Pay as an individual`), + settlePersonal: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pago ${formattedAmount} como individuo` : `Pago individual`), settlePayment: ({formattedAmount}: SettleExpensifyCardParams) => `Pagar ${formattedAmount}`, - settleBusiness: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pay ${formattedAmount} as a business` : `Pay as a business`), + settleBusiness: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pagar ${formattedAmount} como negocio` : `Pagar como empresa`), + payElsewhere: ({formattedAmount}: SettleExpensifyCardParams) => (formattedAmount ? `Pagar ${formattedAmount} de otra forma` : `Pagar de otra forma`), nextStep: 'Pasos Siguientes', finished: 'Finalizado', sendInvoice: ({amount}: RequestAmountParams) => `Enviar factura de ${amount}`, From bb88d41d64db56d74d10aec9c5805ae51036d724 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Wed, 29 May 2024 16:09:31 +0200 Subject: [PATCH 19/20] Update back title inside the submenu --- src/components/PopoverMenu.tsx | 12 ++++++++++-- src/components/SettlementButton.tsx | 1 + src/languages/en.ts | 1 + src/languages/es.ts | 1 + 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index ae7aa14a7080..4635fe5d0720 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -5,6 +5,7 @@ import {View} from 'react-native'; import type {ModalProps} from 'react-native-modal'; import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager'; import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; +import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import CONST from '@src/CONST'; @@ -27,6 +28,9 @@ type PopoverMenuItem = MenuItemProps & { /** Sub menu items to be rendered after a menu item is selected */ subMenuItems?: PopoverMenuItem[]; + /** Back button text to be shown if sub menu items are opened */ + backButtonText?: string; + /** Determines whether the menu item is disabled or not */ disabled?: boolean; }; @@ -92,6 +96,7 @@ function PopoverMenu({ shouldSetModalVisibility = true, }: PopoverMenuProps) { const styles = useThemeStyles(); + const theme = useTheme(); const {isSmallScreenWidth} = useWindowDimensions(); const selectedItemIndex = useRef(null); @@ -127,13 +132,16 @@ function PopoverMenu({ const renderBackButtonItem = () => { const previousMenuItems = getPreviousSubMenu(); const previouslySelectedItem = previousMenuItems[enteredSubMenuIndexes[enteredSubMenuIndexes.length - 1]]; + const hasBackButtonText = !!previouslySelectedItem.backButtonText; return ( { diff --git a/src/components/SettlementButton.tsx b/src/components/SettlementButton.tsx index 7ddbfa6e4928..b6e2a753c829 100644 --- a/src/components/SettlementButton.tsx +++ b/src/components/SettlementButton.tsx @@ -206,6 +206,7 @@ function SettlementButton({ text: translate('iou.settlePersonal', {formattedAmount}), icon: Expensicons.User, value: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + backButtonText: translate('iou.individual'), subMenuItems: [ { text: translate('iou.payElsewhere', {formattedAmount: ''}), diff --git a/src/languages/en.ts b/src/languages/en.ts index dc0c0d5a8371..5c49260cd734 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -673,6 +673,7 @@ export default { deleteConfirmation: 'Are you sure that you want to delete this expense?', settledExpensify: 'Paid', settledElsewhere: 'Paid elsewhere', + individual: 'Individual', 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 ffb2fe312dab..db43845d98fc 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -666,6 +666,7 @@ export default { deleteConfirmation: '¿Estás seguro de que quieres eliminar esta solicitud?', settledExpensify: 'Pagado', settledElsewhere: 'Pagado de otra forma', + individual: 'Individual', 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}`, From 9b7056ffbbb3d54f7f81a689b8d4b1babc9d0be4 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Fri, 31 May 2024 09:46:06 +0200 Subject: [PATCH 20/20] Minor UI fix --- src/components/MenuItem.tsx | 2 +- src/components/PopoverMenu.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index b6f378763659..0fcc12ec50e0 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -360,7 +360,7 @@ function MenuItem( const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const combinedStyle = [style, styles.popoverMenuItem]; + const combinedStyle = [styles.popoverMenuItem, style]; const {shouldUseNarrowLayout} = useResponsiveLayout(); const {isExecuting, singleExecution, waitForNavigate} = useContext(MenuItemGroupContext) ?? {}; diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx index c498c49eb47b..7e72056ac21f 100644 --- a/src/components/PopoverMenu.tsx +++ b/src/components/PopoverMenu.tsx @@ -139,6 +139,7 @@ function PopoverMenu({ key={previouslySelectedItem.text} icon={Expensicons.BackArrow} iconFill={theme.icon} + style={hasBackButtonText ? styles.pv0 : undefined} title={hasBackButtonText ? previouslySelectedItem.backButtonText : previouslySelectedItem.text} titleStyle={hasBackButtonText ? styles.createMenuHeaderText : undefined} shouldShowBasicTitle={hasBackButtonText}