From 97b00d211a486f7c94397bcbc11413036ed45f2e Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 17 Aug 2023 18:55:01 +0100 Subject: [PATCH 01/11] Refactor the money request editing permissions --- .../ReportActionItem/MoneyRequestView.js | 4 +- src/libs/ReportUtils.js | 88 ++++++++++++------- 2 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index c05cf14f2fc1..61701c8d4025 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -71,9 +71,7 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, polic const formattedTransactionAmount = transactionAmount && transactionCurrency && CurrencyUtils.convertToDisplayString(transactionAmount, transactionCurrency); const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID); - const isAdmin = Policy.isAdminOfFreePolicy([policy]) && ReportUtils.isExpenseReport(moneyRequestReport); - const isRequestor = ReportUtils.isMoneyRequestReport(moneyRequestReport) && lodashGet(session, 'accountID', null) === parentReportAction.actorAccountID; - const canEdit = !isSettled && (isAdmin || isRequestor); + const canEdit = ReportUtils.canEditMoneyRequest(parentReportAction); let description = `${translate('iou.amount')} • ${translate('iou.cash')}`; if (isSettled) { diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 521edc35e7b7..4d43f24d8c91 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -186,27 +186,6 @@ function sortReportsByLastRead(reports) { .value(); } -/** - * Can only edit if: - * - * - It was written by the current user - * - It's an ADDCOMMENT that is not an attachment - * - It's not pending deletion - * - * @param {Object} reportAction - * @returns {Boolean} - */ -function canEditReportAction(reportAction) { - return ( - reportAction.actorAccountID === currentUserAccountID && - reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT && - !isReportMessageAttachment(lodashGet(reportAction, ['message', 0], {})) && - !ReportActionsUtils.isDeletedAction(reportAction) && - !ReportActionsUtils.isCreatedTaskReportAction(reportAction) && - reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE - ); -} - /** * Whether the Money Request report is settled * @@ -545,6 +524,15 @@ function isArchivedRoom(report) { return lodashGet(report, ['statusNum']) === CONST.REPORT.STATUS.CLOSED && lodashGet(report, ['stateNum']) === CONST.REPORT.STATE_NUM.SUBMITTED; } +/** + * @param {String} policyID + * @returns {Object} + */ +function getPolicy(policyID) { + const policy = lodashGet(allPolicies, `${ONYXKEYS.COLLECTION.POLICY}${policyID}`) || {}; + return policy; +} + /** * Get the policy name from a given report * @param {Object} report @@ -1229,6 +1217,54 @@ function getTransactionDetails(transaction) { }; } +/** + * Can only edit if: + * + * - in case of IOU report + * - the current user is the requestor + * - in case of expense report + * - the current user is the requestor + * - or the user is an admin on the policy the expense report is tied to + * + * @param {Object} reportAction + * @returns {Boolean} + */ +function canEditMoneyRequest(reportAction) { + // If the report action i snot IOU type, return true early + if (reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { + return true; + } + const moneyRequestReport = getReport(reportAction.reportID); + const isReportSettled = isSettled(moneyRequestReport.reportID); + const isAdmin = isExpenseReport(moneyRequestReport) && lodashGet(getPolicy(moneyRequestReport.policyID), 'role', '') === CONST.POLICY.ROLE.ADMIN; + const isRequestor = currentUserAccountID === reportAction.actorAccountID; + return !isReportSettled && (isAdmin || isRequestor); +} + +/** + * Can only edit if: + * + * - It was written by the current user + * - It's an ADDCOMMENT that is not an attachment + * - It's money request where conditions for editability are defined in canEditMoneyRequest method + * - It's not pending deletion + * + * @param {Object} reportAction + * @returns {Boolean} + */ +function canEditReportAction(reportAction) { + const isCommentOrIOU = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT || reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU; + return ( + reportAction.actorAccountID === currentUserAccountID && + isCommentOrIOU && + canEditMoneyRequest(reportAction) && // Returns true for non-IOU actions + !isReportMessageAttachment(lodashGet(reportAction, ['message', 0], {})) && + !ReportActionsUtils.isDeletedAction(reportAction) && + !ReportActionsUtils.isCreatedTaskReportAction(reportAction) && + reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE + ); +} + /** * Given a parent IOU report action get report name for the LHN. * @@ -2980,15 +3016,6 @@ function getReportOfflinePendingActionAndErrors(report) { return {addWorkspaceRoomOrChatPendingAction, addWorkspaceRoomOrChatErrors}; } -/** - * @param {String} policyID - * @returns {Object} - */ -function getPolicy(policyID) { - const policy = lodashGet(allPolicies, `${ONYXKEYS.COLLECTION.POLICY}${policyID}`) || {}; - return policy; -} - /* * @param {Object|null} report * @returns {Boolean} @@ -3260,4 +3287,5 @@ export { getTransactionReportName, getTransactionDetails, getTaskAssigneeChatOnyxData, + canEditMoneyRequest, }; From 738b328d02c1b769acca7aefcab2cb95456e6d48 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 17 Aug 2023 19:32:01 +0100 Subject: [PATCH 02/11] Editing from the popover menu --- .../ReportActionItem/MoneyRequestAction.js | 11 +++--- src/languages/en.js | 2 +- src/languages/es.js | 2 +- src/libs/ReportUtils.js | 27 ++++++++++++++ .../report/ContextMenu/ContextMenuActions.js | 37 +++++++++++++------ 5 files changed, 61 insertions(+), 18 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestAction.js b/src/components/ReportActionItem/MoneyRequestAction.js index 2e6d07743443..ee22cacbc663 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.js +++ b/src/components/ReportActionItem/MoneyRequestAction.js @@ -95,8 +95,8 @@ function MoneyRequestAction(props) { } // If the childReportID is not present, we need to create a new thread - const childReportID = lodashGet(props.action, 'childReportID', '0'); - if (childReportID === '0') { + const childReportID = lodashGet(props.action, 'childReportID', 0); + if (!childReportID) { const participantAccountIDs = _.uniq([props.session.accountID, Number(props.action.actorAccountID)]); const thread = ReportUtils.buildOptimisticChatReport( participantAccountIDs, @@ -116,10 +116,11 @@ function MoneyRequestAction(props) { const userLogins = PersonalDetailsUtils.getLoginsByAccountIDs(thread.participantAccountIDs); Report.openReport(thread.reportID, userLogins, thread, props.action.reportActionID); Navigation.navigate(ROUTES.getReportRoute(thread.reportID)); - } else { - Report.openReport(childReportID); - Navigation.navigate(ROUTES.getReportRoute(childReportID)); + return; } + + Report.openReport(childReportID); + Navigation.navigate(ROUTES.getReportRoute(childReportID)); }; let shouldShowPendingConversionMessage = false; diff --git a/src/languages/en.js b/src/languages/en.js index 4ce07f7e00ca..7209a7002994 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -273,7 +273,7 @@ export default { copyEmailToClipboard: 'Copy email to clipboard', markAsUnread: 'Mark as unread', markAsRead: 'Mark as read', - editComment: 'Edit comment', + editAction: ({action}) => `Edit ${ReportActionsUtils.isMoneyRequestAction(action) ? 'request' : 'comment'}`, deleteAction: ({action}) => `Delete ${ReportActionsUtils.isMoneyRequestAction(action) ? 'request' : 'comment'}`, deleteConfirmation: ({action}) => `Are you sure you want to delete this ${ReportActionsUtils.isMoneyRequestAction(action) ? 'request' : 'comment'}?`, onlyVisible: 'Only visible to', diff --git a/src/languages/es.js b/src/languages/es.js index 7cee163470f3..653ee4be4277 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -272,7 +272,7 @@ export default { copyEmailToClipboard: 'Copiar email al portapapeles', markAsUnread: 'Marcar como no leído', markAsRead: 'Marcar como leído', - editComment: 'Editar comentario', + editAction: ({action}) => `Edit ${ReportActionsUtils.isMoneyRequestAction(action) ? 'pedido' : 'comentario'}`, deleteAction: ({action}) => `Eliminar ${ReportActionsUtils.isMoneyRequestAction(action) ? 'pedido' : 'comentario'}`, deleteConfirmation: ({action}) => `¿Estás seguro de que quieres eliminar este ${ReportActionsUtils.isMoneyRequestAction(action) ? 'pedido' : 'comentario'}`, onlyVisible: 'Visible sólo para', diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 4d43f24d8c91..62fced99114f 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -14,6 +14,7 @@ import ROUTES from '../ROUTES'; import * as NumberUtils from './NumberUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; import * as TransactionUtils from './TransactionUtils'; +import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import Permissions from './Permissions'; import DateUtils from './DateUtils'; import linkingConfig from './Navigation/linkingConfig'; @@ -2371,6 +2372,31 @@ function buildOptimisticTaskReport(ownerAccountID, assigneeAccountID = 0, parent }; } +/** + * A helper method to create transaction thread + * + * @param {Object} reportAction - the parent IOU report action from which to create the thread + * +* @returns {Object} + */ +function buildTransactionThread(reportAction) { + const participantAccountIDs = _.uniq([currentUserAccountID, Number(reportAction.actorAccountID)]); + return buildOptimisticChatReport( + participantAccountIDs, + getTransactionReportName(reportAction), + '', + lodashGet(getReport(reportAction.reportID), 'policyID', CONST.POLICY.OWNER_EMAIL_FAKE), + CONST.POLICY.OWNER_ACCOUNT_ID_FAKE, + false, + '', + undefined, + undefined, + CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, + reportAction.reportActionID, + reportAction.reportID, + ); +} + /** * @param {Object} report * @returns {Boolean} @@ -3288,4 +3314,5 @@ export { getTransactionDetails, getTaskAssigneeChatOnyxData, canEditMoneyRequest, + buildTransactionThread, }; diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index e66c61b1122f..eec9ad1d4dcb 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -7,7 +7,8 @@ import * as Report from '../../../../libs/actions/Report'; import * as Download from '../../../../libs/actions/Download'; import Clipboard from '../../../../libs/Clipboard'; import * as ReportUtils from '../../../../libs/ReportUtils'; -import * as ReportActionUtils from '../../../../libs/ReportActionsUtils'; +import * as ReportActionsUtils from '../../../../libs/ReportActionsUtils'; +import * as PersonalDetailsUtils from '../../../../libs/PersonalDetailsUtils'; import ReportActionComposeFocusManager from '../../../../libs/ReportActionComposeFocusManager'; import {hideContextMenu, showDeleteModal} from './ReportActionContextMenu'; import CONST from '../../../../CONST'; @@ -43,7 +44,7 @@ export default [ { isAnonymousAction: false, shouldKeepOpen: true, - shouldShow: (type, reportAction) => type === CONTEXT_MENU_TYPES.REPORT_ACTION && _.has(reportAction, 'message') && !ReportActionUtils.isMessageDeleted(reportAction), + shouldShow: (type, reportAction) => type === CONTEXT_MENU_TYPES.REPORT_ACTION && _.has(reportAction, 'message') && !ReportActionsUtils.isMessageDeleted(reportAction), renderContent: (closePopover, {reportID, reportAction, close: closeManually, openContextMenu}) => { const isMini = !closePopover; @@ -96,7 +97,7 @@ export default [ shouldShow: (type, reportAction) => { const message = _.last(lodashGet(reportAction, 'message', [{}])); const isAttachment = _.has(reportAction, 'isAttachment') ? reportAction.isAttachment : ReportUtils.isReportMessageAttachment(message); - return isAttachment && message.html !== CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML && reportAction.reportActionID && !ReportActionUtils.isMessageDeleted(reportAction); + return isAttachment && message.html !== CONST.ATTACHMENT_UPLOADING_MESSAGE_HTML && reportAction.reportActionID && !ReportActionsUtils.isMessageDeleted(reportAction); }, onPress: (closePopover, {reportAction}) => { const message = _.last(lodashGet(reportAction, 'message', [{}])); @@ -125,7 +126,7 @@ export default [ } const isCommentAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT && !ReportUtils.isThreadFirstChat(reportAction, reportID); const isReportPreviewAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW; - const isIOUAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && !ReportActionUtils.isSplitBillAction(reportAction); + const isIOUAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && !ReportActionsUtils.isSplitBillAction(reportAction); return isCommentAction || isReportPreviewAction || isIOUAction; }, onPress: (closePopover, {reportAction, reportID}) => { @@ -179,15 +180,15 @@ export default [ reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.TASKCANCELLED && reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED && reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.TASKREOPENED && - !ReportActionUtils.isCreatedTaskReportAction(reportAction) && + !ReportActionsUtils.isCreatedTaskReportAction(reportAction) && !ReportUtils.isReportMessageAttachment(_.last(lodashGet(reportAction, ['message'], [{}]))) && - !ReportActionUtils.isMessageDeleted(reportAction), + !ReportActionsUtils.isMessageDeleted(reportAction), // If return value is true, we switch the `text` and `icon` on // `ContextMenuItem` with `successText` and `successIcon` which will fallback to // the `text` and `icon` onPress: (closePopover, {reportAction, selection}) => { - const isReportPreviewAction = ReportActionUtils.isReportPreviewAction(reportAction); + const isReportPreviewAction = ReportActionsUtils.isReportPreviewAction(reportAction); const message = _.last(lodashGet(reportAction, 'message', [{}])); const messageHtml = lodashGet(message, 'html', ''); @@ -195,7 +196,7 @@ export default [ if (!isAttachment) { const content = selection || messageHtml; if (isReportPreviewAction) { - const iouReport = ReportUtils.getReport(ReportActionUtils.getIOUReportIDFromReportActionPreview(reportAction)); + const iouReport = ReportUtils.getReport(ReportActionsUtils.getIOUReportIDFromReportActionPreview(reportAction)); const displayMessage = ReportUtils.getReportPreviewMessage(iouReport, reportAction); Clipboard.setString(displayMessage); } else if (content) { @@ -229,7 +230,7 @@ export default [ // Only hide the copylink menu item when context menu is opened over img element. const isAttachmentTarget = lodashGet(menuTarget, 'tagName') === 'IMG' && isAttachment; - return Permissions.canUseCommentLinking(betas) && type === CONTEXT_MENU_TYPES.REPORT_ACTION && !isAttachmentTarget && !ReportActionUtils.isMessageDeleted(reportAction); + return Permissions.canUseCommentLinking(betas) && type === CONTEXT_MENU_TYPES.REPORT_ACTION && !isAttachmentTarget && !ReportActionsUtils.isMessageDeleted(reportAction); }, onPress: (closePopover, {reportAction, reportID}) => { Environment.getEnvironmentURL().then((environmentURL) => { @@ -274,11 +275,25 @@ export default [ { isAnonymousAction: false, - textTranslateKey: 'reportActionContextMenu.editComment', + textTranslateKey: 'reportActionContextMenu.editAction', icon: Expensicons.Pencil, shouldShow: (type, reportAction, isArchivedRoom, betas, menuTarget, isChronosReport) => type === CONTEXT_MENU_TYPES.REPORT_ACTION && ReportUtils.canEditReportAction(reportAction) && !isArchivedRoom && !isChronosReport, onPress: (closePopover, {reportID, reportAction, draftMessage}) => { + if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { + hideContextMenu(false); + const childReportID = lodashGet(reportAction, 'childReportID', 0); + if (!childReportID) { + const thread = ReportUtils.buildTransactionThread(reportAction); + const userLogins = PersonalDetailsUtils.getLoginsByAccountIDs(thread.participantAccountIDs); + Report.openReport(thread.reportID, userLogins, thread, reportAction.reportActionID); + Navigation.navigate(ROUTES.getReportRoute(thread.reportID)); + return; + } + Report.openReport(childReportID); + Navigation.navigate(ROUTES.getReportRoute(childReportID)); + return; + } const editAction = () => Report.saveReportActionDraft(reportID, reportAction, _.isEmpty(draftMessage) ? getActionText(reportAction) : ''); if (closePopover) { @@ -302,7 +317,7 @@ export default [ ReportUtils.canDeleteReportAction(reportAction, reportID) && !isArchivedRoom && !isChronosReport && - !ReportActionUtils.isMessageDeleted(reportAction), + !ReportActionsUtils.isMessageDeleted(reportAction), onPress: (closePopover, {reportID, reportAction}) => { if (closePopover) { // Hide popover, then call showDeleteConfirmModal From 668b68e6777deae59f6bfae7c76d7a45b902bc46 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 17 Aug 2023 20:05:05 +0100 Subject: [PATCH 03/11] refactor the MoneyRequestAction thread creation --- .../ReportActionItem/MoneyRequestAction.js | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestAction.js b/src/components/ReportActionItem/MoneyRequestAction.js index ee22cacbc663..5d47431bb16c 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.js +++ b/src/components/ReportActionItem/MoneyRequestAction.js @@ -97,28 +97,12 @@ function MoneyRequestAction(props) { // If the childReportID is not present, we need to create a new thread const childReportID = lodashGet(props.action, 'childReportID', 0); if (!childReportID) { - const participantAccountIDs = _.uniq([props.session.accountID, Number(props.action.actorAccountID)]); - const thread = ReportUtils.buildOptimisticChatReport( - participantAccountIDs, - ReportUtils.getTransactionReportName(props.action), - '', - lodashGet(props.iouReport, 'policyID', CONST.POLICY.OWNER_EMAIL_FAKE), - CONST.POLICY.OWNER_ACCOUNT_ID_FAKE, - false, - '', - undefined, - undefined, - CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, - props.action.reportActionID, - props.requestReportID, - ); - + const thread = ReportUtils.buildTransactionThread(props.action); const userLogins = PersonalDetailsUtils.getLoginsByAccountIDs(thread.participantAccountIDs); Report.openReport(thread.reportID, userLogins, thread, props.action.reportActionID); Navigation.navigate(ROUTES.getReportRoute(thread.reportID)); return; } - Report.openReport(childReportID); Navigation.navigate(ROUTES.getReportRoute(childReportID)); }; From a4d6645c141354206ac1bee415fe8aa0691ff885 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 17 Aug 2023 20:08:50 +0100 Subject: [PATCH 04/11] destructure props in MoneyRequestAction --- .../ReportActionItem/MoneyRequestAction.js | 71 ++++++++++--------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestAction.js b/src/components/ReportActionItem/MoneyRequestAction.js index 5d47431bb16c..c02bfbd2eb42 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.js +++ b/src/components/ReportActionItem/MoneyRequestAction.js @@ -58,12 +58,6 @@ const propTypes = { network: networkPropTypes.isRequired, - /** Session info for the currently logged in user. */ - session: PropTypes.shape({ - /** Currently logged in user email */ - email: PropTypes.string, - }), - /** Styles to be assigned to Container */ // eslint-disable-next-line react/forbid-prop-types style: PropTypes.arrayOf(PropTypes.object), @@ -78,28 +72,38 @@ const defaultProps = { iouReport: {}, reportActions: {}, isHovered: false, - session: { - email: null, - }, style: [], }; -function MoneyRequestAction(props) { - const isSplitBillAction = lodashGet(props.action, 'originalMessage.type', '') === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; +function MoneyRequestAction({ + action, + chatReportID, + requestReportID, + isMostRecentIOUReportAction, + contextMenuAnchor, + checkIfContextMenuActive, + chatReport, + iouReport, + reportActions, + isHovered, + network, + style, +}) { + const isSplitBillAction = lodashGet(action, 'originalMessage.type', '') === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; const onIOUPreviewPressed = () => { if (isSplitBillAction) { - const reportActionID = lodashGet(props.action, 'reportActionID', '0'); - Navigation.navigate(ROUTES.getSplitBillDetailsRoute(props.chatReportID, reportActionID)); + const reportActionID = lodashGet(action, 'reportActionID', '0'); + Navigation.navigate(ROUTES.getSplitBillDetailsRoute(chatReportID, reportActionID)); return; } // If the childReportID is not present, we need to create a new thread - const childReportID = lodashGet(props.action, 'childReportID', 0); + const childReportID = lodashGet(action, 'childReportID', 0); if (!childReportID) { - const thread = ReportUtils.buildTransactionThread(props.action); + const thread = ReportUtils.buildTransactionThread(action); const userLogins = PersonalDetailsUtils.getLoginsByAccountIDs(thread.participantAccountIDs); - Report.openReport(thread.reportID, userLogins, thread, props.action.reportActionID); + Report.openReport(thread.reportID, userLogins, thread, action.reportActionID); Navigation.navigate(ROUTES.getReportRoute(thread.reportID)); return; } @@ -108,32 +112,32 @@ function MoneyRequestAction(props) { }; let shouldShowPendingConversionMessage = false; - const isDeletedParentAction = ReportActionsUtils.isDeletedParentAction(props.action); + const isDeletedParentAction = ReportActionsUtils.isDeletedParentAction(action); if ( - !_.isEmpty(props.iouReport) && - !_.isEmpty(props.reportActions) && - props.chatReport.hasOutstandingIOU && - props.isMostRecentIOUReportAction && - props.action.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD && - props.network.isOffline + !_.isEmpty(iouReport) && + !_.isEmpty(reportActions) && + chatReport.hasOutstandingIOU && + isMostRecentIOUReportAction && + action.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD && + network.isOffline ) { - shouldShowPendingConversionMessage = IOUUtils.isIOUReportPendingCurrencyConversion(props.reportActions, props.iouReport); + shouldShowPendingConversionMessage = IOUUtils.isIOUReportPendingCurrencyConversion(reportActions, iouReport); } return isDeletedParentAction ? ( - ${props.translate('parentReportAction.deletedRequest')}`} /> + ${translate('parentReportAction.deletedRequest')}`} /> ) : ( ); } @@ -155,9 +159,6 @@ export default compose( key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`, canEvict: false, }, - session: { - key: ONYXKEYS.SESSION, - }, }), withNetwork(), )(MoneyRequestAction); From 10750140a531fb5b97c58c4bd69d5ee4c0d6c188 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 17 Aug 2023 20:10:03 +0100 Subject: [PATCH 05/11] useLocalize --- src/components/ReportActionItem/MoneyRequestAction.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestAction.js b/src/components/ReportActionItem/MoneyRequestAction.js index c02bfbd2eb42..ddf73f15326e 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.js +++ b/src/components/ReportActionItem/MoneyRequestAction.js @@ -17,12 +17,12 @@ import styles from '../../styles/styles'; import * as IOUUtils from '../../libs/IOUUtils'; import * as ReportUtils from '../../libs/ReportUtils'; import * as Report from '../../libs/actions/Report'; -import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import * as ReportActionsUtils from '../../libs/ReportActionsUtils'; import refPropTypes from '../refPropTypes'; import RenderHTML from '../RenderHTML'; import * as PersonalDetailsUtils from '../../libs/PersonalDetailsUtils'; import reportPropTypes from '../../pages/reportPropTypes'; +import useLocalize from '../../hooks/useLocalize'; const propTypes = { /** All the data of the action */ @@ -61,8 +61,6 @@ const propTypes = { /** Styles to be assigned to Container */ // eslint-disable-next-line react/forbid-prop-types style: PropTypes.arrayOf(PropTypes.object), - - ...withLocalizePropTypes, }; const defaultProps = { @@ -89,6 +87,7 @@ function MoneyRequestAction({ network, style, }) { + const {translate} = useLocalize(); const isSplitBillAction = lodashGet(action, 'originalMessage.type', '') === CONST.IOU.REPORT_ACTION_TYPE.SPLIT; const onIOUPreviewPressed = () => { From 529eadceac59e8e6aa8b97156d3f16a9ecbd3b38 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 17 Aug 2023 20:26:17 +0100 Subject: [PATCH 06/11] Get the correct reportID --- src/components/ReportActionItem/MoneyRequestAction.js | 1 - src/libs/ReportUtils.js | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestAction.js b/src/components/ReportActionItem/MoneyRequestAction.js index ddf73f15326e..474b7fbc1c36 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.js +++ b/src/components/ReportActionItem/MoneyRequestAction.js @@ -146,7 +146,6 @@ MoneyRequestAction.defaultProps = defaultProps; MoneyRequestAction.displayName = 'MoneyRequestAction'; export default compose( - withLocalize, withOnyx({ chatReport: { key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 62fced99114f..8065d32df853 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1235,7 +1235,11 @@ function canEditMoneyRequest(reportAction) { if (reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU) { return true; } - const moneyRequestReport = getReport(reportAction.reportID); + const moneyRequestReportID = lodashGet(reportAction, 'originalMessage.IOUReportID', 0); + if (!moneyRequestReportID) { + return false; + } + const moneyRequestReport = getReport(moneyRequestReportID); const isReportSettled = isSettled(moneyRequestReport.reportID); const isAdmin = isExpenseReport(moneyRequestReport) && lodashGet(getPolicy(moneyRequestReport.policyID), 'role', '') === CONST.POLICY.ROLE.ADMIN; const isRequestor = currentUserAccountID === reportAction.actorAccountID; From b6a8b1143bdc4e8f4af569fb2ed1a004921deae2 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 17 Aug 2023 20:26:51 +0100 Subject: [PATCH 07/11] Prettier --- src/libs/ReportUtils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 8065d32df853..229ed4d45bca 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2380,8 +2380,8 @@ function buildOptimisticTaskReport(ownerAccountID, assigneeAccountID = 0, parent * A helper method to create transaction thread * * @param {Object} reportAction - the parent IOU report action from which to create the thread - * -* @returns {Object} + * + * @returns {Object} */ function buildTransactionThread(reportAction) { const participantAccountIDs = _.uniq([currentUserAccountID, Number(reportAction.actorAccountID)]); From 8936a08a802c71a0635d3a0a565eaef20395f730 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 17 Aug 2023 21:07:19 +0100 Subject: [PATCH 08/11] Remove unused code --- .../ReportActionItem/MoneyRequestView.js | 16 +--------------- src/libs/ReportUtils.js | 1 - 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 61701c8d4025..40a70af85ece 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -1,12 +1,10 @@ import React from 'react'; import {View, Image} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import reportPropTypes from '../../pages/reportPropTypes'; import ONYXKEYS from '../../ONYXKEYS'; import ROUTES from '../../ROUTES'; -import * as Policy from '../../libs/actions/Policy'; import Navigation from '../../libs/Navigation/Navigation'; import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../withCurrentUserPersonalDetails'; import compose from '../../libs/compose'; @@ -40,12 +38,6 @@ const propTypes = { avatar: PropTypes.string, }), - /** Session info for the currently logged in user. */ - session: PropTypes.shape({ - /** Currently logged in user email */ - email: PropTypes.string, - }), - /** Whether we should display the horizontal rule below the component */ shouldShowHorizontalRule: PropTypes.bool.isRequired, @@ -55,12 +47,9 @@ const propTypes = { const defaultProps = { parentReport: {}, policy: null, - session: { - email: null, - }, }; -function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, policy, session}) { +function MoneyRequestView({report, parentReport, shouldShowHorizontalRule}) { const {isSmallScreenWidth} = useWindowDimensions(); const {translate} = useLocalize(); @@ -137,8 +126,5 @@ export default compose( policy: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, }, - session: { - key: ONYXKEYS.SESSION, - }, }), )(MoneyRequestView); diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 229ed4d45bca..520ccb5914b8 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -14,7 +14,6 @@ import ROUTES from '../ROUTES'; import * as NumberUtils from './NumberUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; import * as TransactionUtils from './TransactionUtils'; -import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import Permissions from './Permissions'; import DateUtils from './DateUtils'; import linkingConfig from './Navigation/linkingConfig'; From 4f0fac408c2ae7e507a90870a8ac20fda5ce01b3 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 24 Aug 2023 02:10:03 +0100 Subject: [PATCH 09/11] Resolve merge conflicts correctly --- .../ReportActionItem/MoneyRequestView.js | 1 + src/libs/ReportUtils.js | 17 +---------------- .../report/ContextMenu/ContextMenuActions.js | 12 ------------ 3 files changed, 2 insertions(+), 28 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index fd10bc3e5216..fc26522695ad 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -3,6 +3,7 @@ import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; import reportPropTypes from '../../pages/reportPropTypes'; +import lodashGet from 'lodash/get'; import ONYXKEYS from '../../ONYXKEYS'; import ROUTES from '../../ROUTES'; import Navigation from '../../libs/Navigation/Navigation'; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 44ab7f067014..d3525dd8657f 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1288,7 +1288,7 @@ function canEditReportAction(reportAction) { !ReportActionsUtils.isDeletedAction(reportAction) && !ReportActionsUtils.isCreatedTaskReportAction(reportAction) && reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE - ) + ); } /** @@ -3160,17 +3160,6 @@ function getReportOfflinePendingActionAndErrors(report) { return {addWorkspaceRoomOrChatPendingAction, addWorkspaceRoomOrChatErrors}; } -<<<<<<< HEAD -======= -/** - * @param {String} policyID - * @returns {Object} - */ -function getPolicy(policyID) { - const policy = lodashGet(allPolicies, `${ONYXKEYS.COLLECTION.POLICY}${policyID}`) || {}; - return policy; -} - /** * @param {String} policyOwner * @returns {String|null} @@ -3188,7 +3177,6 @@ function getPolicyExpenseChatReportIDByOwner(policyOwner) { return expenseChat.reportID; } ->>>>>>> main /* * @param {Object|null} report * @returns {Boolean} @@ -3486,12 +3474,9 @@ export { getTransactionReportName, getTransactionDetails, getTaskAssigneeChatOnyxData, -<<<<<<< HEAD canEditMoneyRequest, buildTransactionThread, -======= areAllRequestsBeingSmartScanned, getReportPreviewDisplayTransactions, getTransactionsWithReceipts, ->>>>>>> main }; diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 3f663db72af4..ac51319e71b8 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -176,14 +176,6 @@ export default [ successIcon: Expensicons.Checkmark, shouldShow: (type, reportAction) => type === CONTEXT_MENU_TYPES.REPORT_ACTION && -<<<<<<< HEAD - reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.IOU && - reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.TASKCANCELLED && - reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED && - reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.TASKREOPENED && - !ReportActionsUtils.isCreatedTaskReportAction(reportAction) && -======= ->>>>>>> main !ReportUtils.isReportMessageAttachment(_.last(lodashGet(reportAction, ['message'], [{}]))) && !ReportActionsUtils.isMessageDeleted(reportAction), @@ -191,12 +183,8 @@ export default [ // `ContextMenuItem` with `successText` and `successIcon` which will fallback to // the `text` and `icon` onPress: (closePopover, {reportAction, selection}) => { -<<<<<<< HEAD - const isReportPreviewAction = ReportActionsUtils.isReportPreviewAction(reportAction); -======= const isTaskAction = ReportActionUtils.isTaskAction(reportAction); const isReportPreviewAction = ReportActionUtils.isReportPreviewAction(reportAction); ->>>>>>> main const message = _.last(lodashGet(reportAction, 'message', [{}])); const originalMessage = _.get(reportAction, 'originalMessage', {}); const messageHtml = isTaskAction ? lodashGet(originalMessage, 'html', '') : lodashGet(message, 'html', ''); From 2030d6f77d1d5e02b77131857db32d3926b6220e Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Fri, 25 Aug 2023 11:32:23 +0100 Subject: [PATCH 10/11] Address lint --- .../ReportActionItem/MoneyRequestView.js | 23 ++----------------- .../report/ContextMenu/ContextMenuActions.js | 7 +++--- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index fc26522695ad..306adf6bdc39 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -1,9 +1,9 @@ import React from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import reportPropTypes from '../../pages/reportPropTypes'; -import lodashGet from 'lodash/get'; import ONYXKEYS from '../../ONYXKEYS'; import ROUTES from '../../ROUTES'; import Navigation from '../../libs/Navigation/Navigation'; @@ -35,21 +35,6 @@ const propTypes = { /** The expense report or iou report (only will have a value if this is a transaction thread) */ parentReport: iouReportPropTypes, - /** The policy object for the current route */ - policy: PropTypes.shape({ - /** The name of the policy */ - name: PropTypes.string, - - /** The URL for the policy avatar */ - avatar: PropTypes.string, - }), - - /** Session info for the currently logged in user. */ - session: PropTypes.shape({ - /** Currently logged in user email */ - email: PropTypes.string, - }), - /** The transaction associated with the transactionThread */ transaction: transactionPropTypes, @@ -61,10 +46,6 @@ const propTypes = { const defaultProps = { parentReport: {}, - policy: null, - session: { - email: null, - }, transaction: { amount: 0, currency: CONST.CURRENCY.USD, @@ -72,7 +53,7 @@ const defaultProps = { }, }; -function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, policy, session, transaction}) { +function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, transaction}) { const {isSmallScreenWidth} = useWindowDimensions(); const {translate} = useLocalize(); diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index ac51319e71b8..efb10f18e3f9 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -22,6 +22,7 @@ import MiniQuickEmojiReactions from '../../../../components/Reactions/MiniQuickE import Navigation from '../../../../libs/Navigation/Navigation'; import ROUTES from '../../../../ROUTES'; + /** * Gets the HTML version of the message in an action. * @param {Object} reportAction @@ -183,8 +184,8 @@ export default [ // `ContextMenuItem` with `successText` and `successIcon` which will fallback to // the `text` and `icon` onPress: (closePopover, {reportAction, selection}) => { - const isTaskAction = ReportActionUtils.isTaskAction(reportAction); - const isReportPreviewAction = ReportActionUtils.isReportPreviewAction(reportAction); + const isTaskAction = ReportActionsUtils.isTaskAction(reportAction); + const isReportPreviewAction = ReportActionsUtils.isReportPreviewAction(reportAction); const message = _.last(lodashGet(reportAction, 'message', [{}])); const originalMessage = _.get(reportAction, 'originalMessage', {}); const messageHtml = isTaskAction ? lodashGet(originalMessage, 'html', '') : lodashGet(message, 'html', ''); @@ -196,7 +197,7 @@ export default [ const iouReport = ReportUtils.getReport(ReportActionsUtils.getIOUReportIDFromReportActionPreview(reportAction)); const displayMessage = ReportUtils.getReportPreviewMessage(iouReport, reportAction); Clipboard.setString(displayMessage); - } else if (ReportActionUtils.isModifiedExpenseAction(reportAction)) { + } else if (ReportActionsUtils.isModifiedExpenseAction(reportAction)) { const modifyExpenseMessage = ReportUtils.getModifiedExpenseMessage(reportAction); Clipboard.setString(modifyExpenseMessage); } else if (content) { From 6c8292cd197035e557132ee107bae880333fe54a Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Fri, 25 Aug 2023 12:12:00 +0100 Subject: [PATCH 11/11] Prettier --- src/pages/home/report/ContextMenu/ContextMenuActions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index efb10f18e3f9..a3621da3e820 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -22,7 +22,6 @@ import MiniQuickEmojiReactions from '../../../../components/Reactions/MiniQuickE import Navigation from '../../../../libs/Navigation/Navigation'; import ROUTES from '../../../../ROUTES'; - /** * Gets the HTML version of the message in an action. * @param {Object} reportAction