Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "fix: Use new ResolveDuplicates when approver is resolving duplicates" #49953

Merged
merged 1 commit into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,25 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type {MoneyRequestPreviewProps, PendingMessageProps} from './types';

function MoneyRequestPreviewContent({
iouReport,
isBillSplit,
session,
action,
personalDetails,
chatReport,
transaction,
contextMenuAnchor,
chatReportID,
reportID,
onPreviewPressed,
containerStyles,
walletTerms,
checkIfContextMenuActive = () => {},
shouldShowPendingConversionMessage = false,
isHovered = false,
isWhisper = false,
transactionViolations,
shouldDisplayContextMenu = true,
iouReportID,
}: MoneyRequestPreviewProps) {
const theme = useTheme();
const styles = useThemeStyles();
Expand All @@ -72,16 +78,6 @@ function MoneyRequestPreviewContent({
const {windowWidth} = useWindowDimensions();
const route = useRoute<RouteProp<TransactionDuplicateNavigatorParamList, typeof SCREENS.TRANSACTION_DUPLICATE.REVIEW>>();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID || '-1'}`);
const [session] = useOnyx(ONYXKEYS.SESSION);
const [iouReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${iouReportID || '-1'}`);

const isMoneyRequestAction = ReportActionsUtils.isMoneyRequestAction(action);
const transactionID = isMoneyRequestAction ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID : '-1';
const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`);
const [walletTerms] = useOnyx(ONYXKEYS.WALLET_TERMS);
const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);

const sessionAccountID = session?.accountID;
const managerID = iouReport?.managerID ?? -1;
Expand Down
36 changes: 31 additions & 5 deletions src/components/ReportActionItem/MoneyRequestPreview/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,44 @@
import lodashIsEmpty from 'lodash/isEmpty';
import React from 'react';
import {useOnyx} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import ONYXKEYS from '@src/ONYXKEYS';
import MoneyRequestPreviewContent from './MoneyRequestPreviewContent';
import type {MoneyRequestPreviewProps} from './types';
import type {MoneyRequestPreviewOnyxProps, MoneyRequestPreviewProps} from './types';

function MoneyRequestPreview(props: MoneyRequestPreviewProps) {
const [iouReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${props.iouReportID || '-1'}`);
// We should not render the component if there is no iouReport and it's not a split or track expense.
// Moved outside of the component scope to allow for easier use of hooks in the main component.
// eslint-disable-next-line react/jsx-props-no-spreading
return lodashIsEmpty(iouReport) && !(props.isBillSplit || props.isTrackExpense) ? null : <MoneyRequestPreviewContent {...props} />;
return lodashIsEmpty(props.iouReport) && !(props.isBillSplit || props.isTrackExpense) ? null : <MoneyRequestPreviewContent {...props} />;
}

MoneyRequestPreview.displayName = 'MoneyRequestPreview';

export default MoneyRequestPreview;
export default withOnyx<MoneyRequestPreviewProps, MoneyRequestPreviewOnyxProps>({
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
},
chatReport: {
key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`,
},
iouReport: {
key: ({iouReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`,
},
session: {
key: ONYXKEYS.SESSION,
},
transaction: {
key: ({action}) => {
const isMoneyRequestAction = ReportActionsUtils.isMoneyRequestAction(action);
const transactionID = isMoneyRequestAction ? ReportActionsUtils.getOriginalMessage(action)?.IOUTransactionID : 0;
return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`;
},
},
walletTerms: {
key: ONYXKEYS.WALLET_TERMS,
},
transactionViolations: {
key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,
},
})(MoneyRequestPreview);
28 changes: 26 additions & 2 deletions src/components/ReportActionItem/MoneyRequestPreview/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,33 @@
import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native';
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import type {ContextMenuAnchor} from '@pages/home/report/ContextMenu/ReportActionContextMenu';
import type * as OnyxTypes from '@src/types/onyx';
import type IconAsset from '@src/types/utils/IconAsset';

type MoneyRequestPreviewProps = {
type MoneyRequestPreviewOnyxProps = {
/** All of the personal details for everyone */
personalDetails: OnyxEntry<OnyxTypes.PersonalDetailsList>;

/** Chat report associated with iouReport */
chatReport: OnyxEntry<OnyxTypes.Report>;

/** IOU report data object */
iouReport: OnyxEntry<OnyxTypes.Report>;

/** Session info for the currently logged in user. */
session: OnyxEntry<OnyxTypes.Session>;

/** The transaction attached to the action.message.iouTransactionID */
transaction: OnyxEntry<OnyxTypes.Transaction>;

/** The transaction violations attached to the action.message.iouTransactionID */
transactionViolations: OnyxCollection<OnyxTypes.TransactionViolation[]>;

/** Information about the user accepting the terms for payments */
walletTerms: OnyxEntry<OnyxTypes.WalletTerms>;
};

type MoneyRequestPreviewProps = MoneyRequestPreviewOnyxProps & {
/** The active IOUReport, used for Onyx subscription */
// The iouReportID is used inside withOnyx HOC
// eslint-disable-next-line react/no-unused-prop-types
Expand Down Expand Up @@ -66,4 +90,4 @@ type PendingProps = {

type PendingMessageProps = PendingProps | NoPendingProps;

export type {MoneyRequestPreviewProps, PendingMessageProps};
export type {MoneyRequestPreviewProps, MoneyRequestPreviewOnyxProps, PendingMessageProps};
24 changes: 0 additions & 24 deletions src/libs/API/parameters/ResolveDuplicatesParams.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,6 @@ export type {default as SendInvoiceParams} from './SendInvoiceParams';
export type {default as PayInvoiceParams} from './PayInvoiceParams';
export type {default as MarkAsCashParams} from './MarkAsCashParams';
export type {default as TransactionMergeParams} from './TransactionMergeParams';
export type {default as ResolveDuplicatesParams} from './ResolveDuplicatesParams';
export type {default as UpdateSubscriptionTypeParams} from './UpdateSubscriptionTypeParams';
export type {default as SignUpUserParams} from './SignUpUserParams';
export type {default as UpdateSubscriptionAutoRenewParams} from './UpdateSubscriptionAutoRenewParams';
Expand Down
2 changes: 0 additions & 2 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,6 @@ const WRITE_COMMANDS = {
PAY_INVOICE: 'PayInvoice',
MARK_AS_CASH: 'MarkAsCash',
TRANSACTION_MERGE: 'Transaction_Merge',
RESOLVE_DUPLICATES: 'ResolveDuplicates',
UPDATE_SUBSCRIPTION_TYPE: 'UpdateSubscriptionType',
SIGN_UP_USER: 'SignUpUser',
UPDATE_SUBSCRIPTION_AUTO_RENEW: 'UpdateSubscriptionAutoRenew',
Expand Down Expand Up @@ -707,7 +706,6 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.PAY_INVOICE]: Parameters.PayInvoiceParams;
[WRITE_COMMANDS.MARK_AS_CASH]: Parameters.MarkAsCashParams;
[WRITE_COMMANDS.TRANSACTION_MERGE]: Parameters.TransactionMergeParams;
[WRITE_COMMANDS.RESOLVE_DUPLICATES]: Parameters.ResolveDuplicatesParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_TYPE]: Parameters.UpdateSubscriptionTypeParams;
[WRITE_COMMANDS.SIGN_UP_USER]: Parameters.SignUpUserParams;
[WRITE_COMMANDS.UPDATE_SUBSCRIPTION_AUTO_RENEW]: Parameters.UpdateSubscriptionAutoRenewParams;
Expand Down
150 changes: 12 additions & 138 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import type {
PayMoneyRequestParams,
ReplaceReceiptParams,
RequestMoneyParams,
ResolveDuplicatesParams,
SendInvoiceParams,
SendMoneyParams,
SetNameValuePairParams,
Expand Down Expand Up @@ -8069,21 +8068,6 @@ function getIOURequestPolicyID(transaction: OnyxEntry<OnyxTypes.Transaction>, re
return workspaceSender?.policyID ?? report?.policyID ?? '-1';
}

function getIOUActionForTransactions(transactionIDList: string[], iouReportID: string): Array<ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU>> {
return Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReportID}`] ?? {})?.filter(
(reportAction): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU> => {
if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) {
return false;
}
const message = ReportActionsUtils.getOriginalMessage(reportAction);
if (!message?.IOUTransactionID) {
return false;
}
return transactionIDList.includes(message.IOUTransactionID);
},
);
}

/** Merge several transactions into one by updating the fields of the one we want to keep and deleting the rest */
function mergeDuplicates(params: TransactionMergeParams) {
const originalSelectedTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${params.transactionID}`];
Expand Down Expand Up @@ -8168,7 +8152,18 @@ function mergeDuplicates(params: TransactionMergeParams) {
},
};

const iouActionsToDelete = getIOUActionForTransactions(params.transactionIDList, params.reportID);
const iouActionsToDelete = Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${params.reportID}`] ?? {})?.filter(
(reportAction): reportAction is ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.IOU> => {
if (!ReportActionsUtils.isMoneyRequestAction(reportAction)) {
return false;
}
const message = ReportActionsUtils.getOriginalMessage(reportAction);
if (!message?.IOUTransactionID) {
return false;
}
return params.transactionIDList.includes(message.IOUTransactionID);
},
);

const deletedTime = DateUtils.getDBTime();
const expenseReportActionsOptimisticData: OnyxUpdate = {
Expand Down Expand Up @@ -8229,125 +8224,6 @@ function mergeDuplicates(params: TransactionMergeParams) {
API.write(WRITE_COMMANDS.TRANSACTION_MERGE, params, {optimisticData, failureData});
}

/** Instead of merging the duplicates, it updates the transaction we want to keep and puts the others on hold without deleting them */
function resolveDuplicates(params: TransactionMergeParams) {
const originalSelectedTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${params.transactionID}`];

const optimisticTransactionData: OnyxUpdate = {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${params.transactionID}`,
value: {
...originalSelectedTransaction,
billable: params.billable,
comment: {
comment: params.comment,
},
category: params.category,
created: params.created,
currency: params.currency,
modifiedMerchant: params.merchant,
reimbursable: params.reimbursable,
tag: params.tag,
},
};

const failureTransactionData: OnyxUpdate = {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${params.transactionID}`,
// eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
value: originalSelectedTransaction as OnyxTypes.Transaction,
};

const optimisticTransactionViolations: OnyxUpdate[] = [...params.transactionIDList, params.transactionID].map((id) => {
const violations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${id}`] ?? [];
const newViolation = {name: CONST.VIOLATIONS.HOLD, type: CONST.VIOLATION_TYPES.VIOLATION};
const updatedViolations = id === params.transactionID ? violations : [...violations, newViolation];
return {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${id}`,
value: updatedViolations.filter((violation) => violation.name !== CONST.VIOLATIONS.DUPLICATED_TRANSACTION),
};
});

const failureTransactionViolations: OnyxUpdate[] = [...params.transactionIDList, params.transactionID].map((id) => {
const violations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${id}`] ?? [];
return {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${id}`,
value: violations,
};
});

const iouActionList = getIOUActionForTransactions(params.transactionIDList, params.reportID);
const transactionThreadReportIDList = iouActionList.map((action) => action?.childReportID);
const orderedTransactionIDList = iouActionList.map((action) => {
const message = ReportActionsUtils.getOriginalMessage(action);
return message?.IOUTransactionID ?? '';
});

const optimisticHoldActions: OnyxUpdate[] = [];
const failureHoldActions: OnyxUpdate[] = [];
const reportActionIDList: string[] = [];
transactionThreadReportIDList.forEach((transactionThreadReportID) => {
const createdReportAction = ReportUtils.buildOptimisticHoldReportAction();
reportActionIDList.push(createdReportAction.reportActionID);
optimisticHoldActions.push({
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`,
value: {
[createdReportAction.reportActionID]: createdReportAction,
},
});
failureHoldActions.push({
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`,
value: {
[createdReportAction.reportActionID]: {
errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericHoldExpenseFailureMessage'),
},
},
});
});

const transactionThreadReportID = getIOUActionForTransactions([params.transactionID], params.reportID)?.[0]?.childReportID;
const optimisticReportAction = ReportUtils.buildOptimisticDismissedViolationReportAction({
reason: 'manual',
violationName: CONST.VIOLATIONS.DUPLICATED_TRANSACTION,
});

const optimisticReportActionData: OnyxUpdate = {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`,
value: {
[optimisticReportAction.reportActionID]: optimisticReportAction,
},
};

const failureReportActionData: OnyxUpdate = {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`,
value: {
[optimisticReportAction.reportActionID]: null,
},
};

const optimisticData: OnyxUpdate[] = [];
const failureData: OnyxUpdate[] = [];

optimisticData.push(optimisticTransactionData, ...optimisticTransactionViolations, ...optimisticHoldActions, optimisticReportActionData);
failureData.push(failureTransactionData, ...failureTransactionViolations, ...failureHoldActions, failureReportActionData);
const {reportID, transactionIDList, receiptID, ...otherParams} = params;

const parameters: ResolveDuplicatesParams = {
...otherParams,
reportActionIDList,
transactionIDList: orderedTransactionIDList,
dismissedViolationReportActionID: optimisticReportAction.reportActionID,
};

API.write(WRITE_COMMANDS.RESOLVE_DUPLICATES, parameters, {optimisticData, failureData});
}

export {
adjustRemainingSplitShares,
getNextApproverAccountID,
Expand Down Expand Up @@ -8419,7 +8295,5 @@ export {
updateMoneyRequestTaxAmount,
updateMoneyRequestTaxRate,
mergeDuplicates,
resolveDuplicates,
prepareToCleanUpMoneyRequest,
};
export type {GPSPoint as GpsPoint, IOURequestType};
Loading
Loading