From 32d135582c6c20e3fa5ab5f0e88ff9a47c9c8532 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 14 Sep 2023 16:43:09 +0200 Subject: [PATCH 01/23] delegate category selection to parent --- .../CategoryPicker/categoryPickerPropTypes.js | 16 ++++------ src/components/CategoryPicker/index.js | 30 ++++--------------- src/pages/iou/MoneyRequestCategoryPage.js | 27 +++++++++++++++-- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/components/CategoryPicker/categoryPickerPropTypes.js b/src/components/CategoryPicker/categoryPickerPropTypes.js index b8e24c199a73..6f2800a5d98f 100644 --- a/src/components/CategoryPicker/categoryPickerPropTypes.js +++ b/src/components/CategoryPicker/categoryPickerPropTypes.js @@ -2,14 +2,11 @@ import PropTypes from 'prop-types'; import categoryPropTypes from '../categoryPropTypes'; const propTypes = { - /** The report ID of the IOU */ - reportID: PropTypes.string.isRequired, - /** The policyID we are getting categories for */ policyID: PropTypes.string, - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.string.isRequired, + /** The selected category of an expense */ + selectedCategory: PropTypes.string, /* Onyx Props */ /** Collection of categories attached to a policy */ @@ -19,18 +16,15 @@ const propTypes = { /** Collection of recently used categories attached to a policy */ policyRecentlyUsedCategories: PropTypes.arrayOf(PropTypes.string), - /* Onyx Props */ - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: PropTypes.shape({ - category: PropTypes.string.isRequired, - }), + /** Callback to fire when a category is pressed */ + onSubmit: PropTypes.func.isRequired, }; const defaultProps = { policyID: '', + selectedCategory: '', policyCategories: {}, policyRecentlyUsedCategories: [], - iou: {}, }; export {propTypes, defaultProps}; diff --git a/src/components/CategoryPicker/index.js b/src/components/CategoryPicker/index.js index 91c7e82e7887..66ac0bf14d4a 100644 --- a/src/components/CategoryPicker/index.js +++ b/src/components/CategoryPicker/index.js @@ -5,15 +5,12 @@ import lodashGet from 'lodash/get'; import ONYXKEYS from '../../ONYXKEYS'; import {propTypes, defaultProps} from './categoryPickerPropTypes'; import styles from '../../styles/styles'; -import Navigation from '../../libs/Navigation/Navigation'; -import ROUTES from '../../ROUTES'; import CONST from '../../CONST'; -import * as IOU from '../../libs/actions/IOU'; import * as OptionsListUtils from '../../libs/OptionsListUtils'; import OptionsSelector from '../OptionsSelector'; import useLocalize from '../../hooks/useLocalize'; -function CategoryPicker({policyCategories, reportID, iouType, iou, policyRecentlyUsedCategories}) { +function CategoryPicker({selectedCategory, policyCategories, policyRecentlyUsedCategories, onSubmit}) { const {translate} = useLocalize(); const [searchValue, setSearchValue] = useState(''); @@ -21,18 +18,18 @@ function CategoryPicker({policyCategories, reportID, iouType, iou, policyRecentl const isCategoriesCountBelowThreshold = policyCategoriesCount < CONST.CATEGORY_LIST_THRESHOLD; const selectedOptions = useMemo(() => { - if (!iou.category) { + if (!selectedCategory) { return []; } return [ { - name: iou.category, + name: selectedCategory, enabled: true, accountID: null, }, ]; - }, [iou.category]); + }, [selectedCategory]); const initialFocusedIndex = useMemo(() => { if (isCategoriesCountBelowThreshold && selectedOptions.length > 0) { @@ -53,20 +50,6 @@ function CategoryPicker({policyCategories, reportID, iouType, iou, policyRecentl const headerMessage = OptionsListUtils.getHeaderMessage(lodashGet(sections, '[0].data.length', 0) > 0, false, searchValue); const shouldShowTextInput = !isCategoriesCountBelowThreshold; - const navigateBack = () => { - Navigation.goBack(ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID)); - }; - - const updateCategory = (category) => { - if (category.searchText === iou.category) { - IOU.resetMoneyRequestCategory(); - } else { - IOU.setMoneyRequestCategory(category.searchText); - } - - navigateBack(); - }; - return ( ); } @@ -97,7 +80,4 @@ export default withOnyx({ policyRecentlyUsedCategories: { key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${policyID}`, }, - iou: { - key: ONYXKEYS.IOU, - }, })(CategoryPicker); diff --git a/src/pages/iou/MoneyRequestCategoryPage.js b/src/pages/iou/MoneyRequestCategoryPage.js index 80b88a762609..adba5755496d 100644 --- a/src/pages/iou/MoneyRequestCategoryPage.js +++ b/src/pages/iou/MoneyRequestCategoryPage.js @@ -10,6 +10,7 @@ import HeaderWithBackButton from '../../components/HeaderWithBackButton'; import CategoryPicker from '../../components/CategoryPicker'; import ONYXKEYS from '../../ONYXKEYS'; import reportPropTypes from '../reportPropTypes'; +import * as IOU from '../../libs/actions/IOU'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -26,13 +27,20 @@ const propTypes = { /** The report currently being used */ report: reportPropTypes, + + /* Onyx Props */ + /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ + iou: PropTypes.shape({ + category: PropTypes.string.isRequired, + }), }; const defaultProps = { report: {}, + iou: {}, }; -function MoneyRequestCategoryPage({route, report}) { +function MoneyRequestCategoryPage({route, report, iou}) { const {translate} = useLocalize(); const reportID = lodashGet(route, 'params.reportID', ''); @@ -42,6 +50,16 @@ function MoneyRequestCategoryPage({route, report}) { Navigation.goBack(ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID)); }; + const updateCategory = (category) => { + if (category.searchText === iou.category) { + IOU.resetMoneyRequestCategory(); + } else { + IOU.setMoneyRequestCategory(category.searchText); + } + + Navigation.goBack(ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID)); + }; + return ( ); @@ -69,4 +87,7 @@ export default withOnyx({ report: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${lodashGet(route, 'params.reportID', '')}`, }, + iou: { + key: ONYXKEYS.IOU, + }, })(MoneyRequestCategoryPage); From d7996869bf22815900c87a80f9ac9e68a1f27626 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 14 Sep 2023 16:44:05 +0200 Subject: [PATCH 02/23] implement edit request category page --- src/CONST.ts | 1 + src/pages/EditRequestCategoryPage.js | 49 ++++++++++++++++++++++++++++ src/pages/EditRequestPage.js | 26 ++++++++++++++- 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/pages/EditRequestCategoryPage.js diff --git a/src/CONST.ts b/src/CONST.ts index 1ef2f3e83246..7b6d1d1d36fb 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1349,6 +1349,7 @@ const CONST = { DATE: 'date', DESCRIPTION: 'description', MERCHANT: 'merchant', + CATEGORY: 'category', }, FOOTER: { EXPENSE_MANAGEMENT_URL: `${USE_EXPENSIFY_URL}/expense-management`, diff --git a/src/pages/EditRequestCategoryPage.js b/src/pages/EditRequestCategoryPage.js new file mode 100644 index 000000000000..ba94c2b40800 --- /dev/null +++ b/src/pages/EditRequestCategoryPage.js @@ -0,0 +1,49 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import ScreenWrapper from '../components/ScreenWrapper'; +import HeaderWithBackButton from '../components/HeaderWithBackButton'; +import Navigation from '../libs/Navigation/Navigation'; +import useLocalize from '../hooks/useLocalize'; +import CategoryPicker from '../components/CategoryPicker'; + +const propTypes = { + /** Transaction default category value */ + defaultCategory: PropTypes.string.isRequired, + + /** The policyID we are getting categories for */ + policyID: PropTypes.string.isRequired, + + /** Callback to fire when the Save button is pressed */ + onSubmit: PropTypes.func.isRequired, +}; + +function EditRequestCategoryPage({defaultCategory, policyID, onSubmit}) { + const {translate} = useLocalize(); + + return ( + + + + + onSubmit({ + category: category.searchText, + }) + } + /> + + ); +} + +EditRequestCategoryPage.propTypes = propTypes; +EditRequestCategoryPage.displayName = 'EditRequestCategoryPage'; + +export default EditRequestCategoryPage; diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index 266515e29c2c..d4fc92c894d0 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -19,6 +19,7 @@ import reportPropTypes from './reportPropTypes'; import * as IOU from '../libs/actions/IOU'; import * as CurrencyUtils from '../libs/CurrencyUtils'; import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView'; +import EditRequestCategoryPage from './EditRequestCategoryPage'; const propTypes = { /** Route from navigation */ @@ -69,7 +70,13 @@ const defaultProps = { function EditRequestPage({report, route, parentReport, policy, session}) { const parentReportAction = ReportActionsUtils.getParentReportAction(report); const transaction = TransactionUtils.getLinkedTransaction(parentReportAction); - const {amount: transactionAmount, currency: transactionCurrency, comment: transactionDescription, merchant: transactionMerchant} = ReportUtils.getTransactionDetails(transaction); + const { + amount: transactionAmount, + currency: transactionCurrency, + comment: transactionDescription, + merchant: transactionMerchant, + category: transactionCategory, + } = ReportUtils.getTransactionDetails(transaction); const defaultCurrency = lodashGet(route, 'params.currency', '') || transactionCurrency; @@ -169,6 +176,23 @@ function EditRequestPage({report, route, parentReport, policy, session}) { ); } + if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.CATEGORY) { + return ( + { + let updatedCategory = transactionChanges.category; + // In case the same category has been selected, do reset of the category. + if (transactionCategory === updatedCategory) { + updatedCategory = ''; + } + editMoneyRequest({category: updatedCategory}); + }} + /> + ); + } + return ; } From da95354c9ad2a170f224a080e4651ef0a0ec2207 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 14 Sep 2023 16:46:25 +0200 Subject: [PATCH 03/23] preview and navigate to edit a category --- .../ReportActionItem/MoneyRequestView.js | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index a9264812b99d..7ad7dc0ce356 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -1,6 +1,7 @@ import React from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import reportPropTypes from '../../pages/reportPropTypes'; @@ -27,6 +28,7 @@ import Image from '../Image'; import ReportActionItemImage from './ReportActionItemImage'; import * as TransactionUtils from '../../libs/TransactionUtils'; import OfflineWithFeedback from '../OfflineWithFeedback'; +import categoryPropTypes from '../categoryPropTypes'; const propTypes = { /** The report currently being looked at */ @@ -35,6 +37,10 @@ const propTypes = { /** The expense report or iou report (only will have a value if this is a transaction thread) */ parentReport: iouReportPropTypes, + /* Onyx Props */ + /** Collection of categories attached to a policy */ + policyCategories: PropTypes.objectOf(categoryPropTypes), + /** The transaction associated with the transactionThread */ transaction: transactionPropTypes, @@ -46,6 +52,7 @@ const propTypes = { const defaultProps = { parentReport: {}, + policyCategories: {}, transaction: { amount: 0, currency: CONST.CURRENCY.USD, @@ -53,7 +60,7 @@ const defaultProps = { }, }; -function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, transaction}) { +function MoneyRequestView({report, parentReport, policyCategories, shouldShowHorizontalRule, transaction}) { const {isSmallScreenWidth} = useWindowDimensions(); const {translate} = useLocalize(); @@ -65,6 +72,7 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, trans currency: transactionCurrency, comment: transactionDescription, merchant: transactionMerchant, + category: transactionCategory, } = ReportUtils.getTransactionDetails(transaction); const isEmptyMerchant = transactionMerchant === '' || transactionMerchant === CONST.TRANSACTION.UNKNOWN_MERCHANT || transactionMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; @@ -72,6 +80,7 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, trans const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID); const canEdit = ReportUtils.canEditMoneyRequest(parentReportAction); + const shouldShowCategory = !_.isEmpty(policyCategories) || !_.isEmpty(transactionCategory); let description = `${translate('iou.amount')} • ${translate('iou.cash')}`; if (isSettled) { @@ -165,6 +174,18 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, trans subtitleTextStyle={styles.textLabelError} /> + {shouldShowCategory && ( + + Navigation.navigate(ROUTES.getEditRequestRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.CATEGORY))} + /> + + )} {shouldShowHorizontalRule && } ); @@ -183,6 +204,9 @@ export default compose( policy: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, }, + policyCategories: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report.policyID}`, + }, session: { key: ONYXKEYS.SESSION, }, From bfc59ba9dcf7275eb7cad57dac477d0576577190 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 14 Sep 2023 17:35:52 +0200 Subject: [PATCH 04/23] prepare api --- src/libs/TransactionUtils.js | 14 +++++++++++++- src/libs/actions/IOU.js | 13 +++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/libs/TransactionUtils.js b/src/libs/TransactionUtils.js index 4ca8b48d284e..73ba6a8116ef 100644 --- a/src/libs/TransactionUtils.js +++ b/src/libs/TransactionUtils.js @@ -141,6 +141,11 @@ function getUpdatedTransaction(transaction, transactionChanges, isFromExpenseRep shouldStopSmartscan = true; } + if (_.has(transactionChanges, 'category')) { + updatedTransaction.modifiedCategory = transactionChanges.category; + shouldStopSmartscan = true; + } + if (shouldStopSmartscan && _.has(transaction, 'receipt') && !_.isEmpty(transaction.receipt) && lodashGet(transaction, 'receipt.state') !== CONST.IOU.RECEIPT_STATE.OPEN) { updatedTransaction.receipt.state = CONST.IOU.RECEIPT_STATE.OPEN; } @@ -151,6 +156,7 @@ function getUpdatedTransaction(transaction, transactionChanges, isFromExpenseRep ...(_.has(transactionChanges, 'amount') && {amount: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), ...(_.has(transactionChanges, 'currency') && {currency: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), ...(_.has(transactionChanges, 'merchant') && {merchant: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), + ...(_.has(transactionChanges, 'category') && {category: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}), }; return updatedTransaction; @@ -232,12 +238,18 @@ function getMerchant(transaction) { } /** - * Return the category from the transaction. This "category" field has no "modified" complement. + * Return the category from the transaction, return the modifiedCategory if present. * * @param {Object} transaction * @return {String} */ function getCategory(transaction) { + const modifiedCategory = lodashGet(transaction, 'modifiedCategory', null); + + if (!_.isNull(modifiedCategory)) { + return modifiedCategory; + } + return lodashGet(transaction, 'category', ''); } diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 8f18119203be..3e23bb596eee 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1121,6 +1121,7 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC created: null, currency: null, merchant: null, + category: null, }, }, }, @@ -1156,6 +1157,18 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC }, ]; + // STEP 5: Use the modifiedCategory as a category on success + if (!_.isUndefined(updatedTransaction.modifiedCategory)) { + successData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, + value: { + category: updatedTransaction.modifiedCategory, + modifiedCategory: null, + }, + }); + } + // STEP 6: Call the API endpoint const {created, amount, currency, comment, merchant, category} = ReportUtils.getTransactionDetails(updatedTransaction); API.write( From 05f020c371399f9d4871287853b61c4bb973da19 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 15 Sep 2023 17:35:06 +0200 Subject: [PATCH 05/23] do not stop smart scan --- src/libs/TransactionUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/TransactionUtils.js b/src/libs/TransactionUtils.js index 73ba6a8116ef..5fc6294aca91 100644 --- a/src/libs/TransactionUtils.js +++ b/src/libs/TransactionUtils.js @@ -143,7 +143,7 @@ function getUpdatedTransaction(transaction, transactionChanges, isFromExpenseRep if (_.has(transactionChanges, 'category')) { updatedTransaction.modifiedCategory = transactionChanges.category; - shouldStopSmartscan = true; + shouldStopSmartscan = false; } if (shouldStopSmartscan && _.has(transaction, 'receipt') && !_.isEmpty(transaction.receipt) && lodashGet(transaction, 'receipt.state') !== CONST.IOU.RECEIPT_STATE.OPEN) { From 636924f0928a253fd6a7efb4d271eba125afdcbc Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 15 Sep 2023 19:07:05 +0200 Subject: [PATCH 06/23] handle a selected category alone --- src/libs/OptionsListUtils.js | 12 ++++++++++++ tests/unit/OptionsListUtilsTest.js | 23 ++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 7629a1acc0a6..8027a30b34a1 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -666,6 +666,18 @@ function getCategoryListSections(categories, recentlyUsedCategories, selectedOpt const numberOfCategories = _.size(categoriesValues); let indexOffset = 0; + if (numberOfCategories === 0 && selectedOptions.length > 0) { + categorySections.push({ + // "Selected" section + title: '', + shouldShow: false, + indexOffset, + data: getCategoryOptionTree(selectedOptions, true), + }); + + return categorySections; + } + if (!_.isEmpty(searchInputValue)) { const searchCategories = _.filter(categoriesValues, (category) => category.name.toLowerCase().includes(searchInputValue.toLowerCase())); diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index f1a251e4e433..ef90c767175e 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -660,6 +660,7 @@ describe('OptionsListUtils', () => { const selectedOptions = [ { name: 'Medical', + enabled: true, }, ]; const smallCategoriesList = { @@ -817,7 +818,7 @@ describe('OptionsListUtils', () => { keyForList: 'Medical', searchText: 'Medical', tooltipText: 'Medical', - isDisabled: true, + isDisabled: false, }, ], }, @@ -1000,6 +1001,23 @@ describe('OptionsListUtils', () => { data: [], }, ]; + const emptyCategoriesList = {}; + const emptySelectedResultList = [ + { + title: '', + shouldShow: false, + indexOffset: 0, + data: [ + { + text: 'Medical', + keyForList: 'Medical', + searchText: 'Medical', + tooltipText: 'Medical', + isDisabled: false, + }, + ], + }, + ]; const smallResult = OptionsListUtils.getNewChatOptions(REPORTS, PERSONAL_DETAILS, [], emptySearch, [], [], false, false, true, smallCategoriesList); expect(smallResult.categoryOptions).toStrictEqual(smallResultList); @@ -1054,6 +1072,9 @@ describe('OptionsListUtils', () => { recentlyUsedCategories, ); expect(largeWrongSearchResult.categoryOptions).toStrictEqual(largeWrongSearchResultList); + + const emptyResult = OptionsListUtils.getNewChatOptions(REPORTS, PERSONAL_DETAILS, [], search, selectedOptions, [], false, false, true, emptyCategoriesList); + expect(emptyResult.categoryOptions).toStrictEqual(emptySelectedResultList); }); it('getCategoryOptionTree()', () => { From 812ea0568c93ef608a43f35013a0a9bef6eff8f5 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 18 Sep 2023 11:05:03 +0200 Subject: [PATCH 07/23] do not use modified category --- src/libs/TransactionUtils.js | 11 ++--------- src/libs/actions/IOU.js | 12 ------------ 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/src/libs/TransactionUtils.js b/src/libs/TransactionUtils.js index 5fc6294aca91..7e768e97b837 100644 --- a/src/libs/TransactionUtils.js +++ b/src/libs/TransactionUtils.js @@ -142,8 +142,7 @@ function getUpdatedTransaction(transaction, transactionChanges, isFromExpenseRep } if (_.has(transactionChanges, 'category')) { - updatedTransaction.modifiedCategory = transactionChanges.category; - shouldStopSmartscan = false; + updatedTransaction.category = transactionChanges.category; } if (shouldStopSmartscan && _.has(transaction, 'receipt') && !_.isEmpty(transaction.receipt) && lodashGet(transaction, 'receipt.state') !== CONST.IOU.RECEIPT_STATE.OPEN) { @@ -238,18 +237,12 @@ function getMerchant(transaction) { } /** - * Return the category from the transaction, return the modifiedCategory if present. + * Return the category from the transaction. This "category" field has no "modified" complement. * * @param {Object} transaction * @return {String} */ function getCategory(transaction) { - const modifiedCategory = lodashGet(transaction, 'modifiedCategory', null); - - if (!_.isNull(modifiedCategory)) { - return modifiedCategory; - } - return lodashGet(transaction, 'category', ''); } diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 16722d4dc70b..9f1d67d1db1d 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1160,18 +1160,6 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC }, ]; - // STEP 5: Use the modifiedCategory as a category on success - if (!_.isUndefined(updatedTransaction.modifiedCategory)) { - successData.push({ - onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, - value: { - category: updatedTransaction.modifiedCategory, - modifiedCategory: null, - }, - }); - } - // STEP 6: Call the API endpoint const {created, amount, currency, comment, merchant, category} = ReportUtils.getTransactionDetails(updatedTransaction); API.write( From 3dd7b5c14b2817594ef19f299b329262174ec61a Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 18 Sep 2023 15:11:26 +0200 Subject: [PATCH 08/23] create getRootParentReport helper --- src/libs/ReportUtils.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 9396ea921b61..7115de23d1a1 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1601,6 +1601,29 @@ function getParentReport(report) { return lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`, {}); } +/** + * Returns the root parentReport if the given report is nested. + * Uses recursion to iterate any depth of nested reports. + * + * @param {Object} report + * @returns {Object} + */ +function getRootParentReport(report) { + if (!report) { + return {}; + } + + // Returns the founded root report, because it does not have a parentReportID + if (!report.parentReportID) { + return report; + } + + const parentReport = getReport(report.parentReportID); + + // Runs recursion to iterate a parent report + return getRootParentReport(parentReport); +} + /** * Get the title for a report. * @@ -3613,6 +3636,7 @@ export { isAllowedToComment, getBankAccountRoute, getParentReport, + getRootParentReport, getTaskParentReportActionIDInAssigneeReport, getReportPreviewMessage, getModifiedExpenseMessage, From d7b6b89b73d20413d809093843fa48941862921e Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 18 Sep 2023 15:12:17 +0200 Subject: [PATCH 09/23] improve conditions of MoneyRequestConfirmationList --- src/components/MoneyRequestConfirmationList.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index da98d324681e..d72860e78a48 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -191,13 +191,19 @@ function MoneyRequestConfirmationList(props) { const {unit, rate, currency} = props.mileageRate; const distance = lodashGet(transaction, 'routes.route0.distance', 0); const shouldCalculateDistanceAmount = props.isDistanceRequest && props.iouAmount === 0; - const shouldCategoryBeEditable = !_.isEmpty(props.policyCategories) && Permissions.canUseCategories(props.betas); + + // A flag for verifying that the current report is a sub-report of a workspace chat + const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(ReportUtils.getReport(props.reportID))), [props.reportID]); + + // A flag for showing the categories field + const shouldShowCategories = isPolicyExpenseChat && Permissions.canUseCategories(props.betas) && !_.isEmpty(props.policyCategories); // Fetches the first tag list of the policy const tagListKey = _.first(_.keys(props.policyTags)); const tagList = lodashGet(props.policyTags, [tagListKey, 'tags'], []); const tagListName = lodashGet(props.policyTags, [tagListKey, 'name'], ''); - const canUseTags = Permissions.canUseTags(props.betas); + // A flag for showing the tags field + const shouldShowTags = isPolicyExpenseChat && Permissions.canUseTags(props.betas) && !_.isEmpty(tagList); const formattedAmount = CurrencyUtils.convertToDisplayString( shouldCalculateDistanceAmount ? DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate) : props.iouAmount, @@ -510,7 +516,7 @@ function MoneyRequestConfirmationList(props) { disabled={didConfirm || props.isReadOnly || !isTypeRequest} /> )} - {shouldCategoryBeEditable && ( + {shouldShowCategories && ( )} - {canUseTags && !!tagList && ( + {shouldShowTags && ( Date: Mon, 18 Sep 2023 15:14:09 +0200 Subject: [PATCH 10/23] improve conditions of MoneyRequestView --- .../ReportActionItem/MoneyRequestView.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index eb08639d8d8e..8232f8618f2c 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useMemo} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; @@ -10,6 +10,7 @@ import ROUTES from '../../ROUTES'; import Navigation from '../../libs/Navigation/Navigation'; import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../withCurrentUserPersonalDetails'; import compose from '../../libs/compose'; +import Permissions from '../../libs/Permissions'; import MenuItemWithTopDescription from '../MenuItemWithTopDescription'; import styles from '../../styles/styles'; import * as ReportUtils from '../../libs/ReportUtils'; @@ -31,6 +32,9 @@ import OfflineWithFeedback from '../OfflineWithFeedback'; import categoryPropTypes from '../categoryPropTypes'; const propTypes = { + /** List of betas available to current user */ + betas: PropTypes.arrayOf(PropTypes.string), + /** The report currently being looked at */ report: reportPropTypes.isRequired, @@ -51,6 +55,7 @@ const propTypes = { }; const defaultProps = { + betas: [], parentReport: {}, policyCategories: {}, transaction: { @@ -60,7 +65,7 @@ const defaultProps = { }, }; -function MoneyRequestView({report, parentReport, policyCategories, shouldShowHorizontalRule, transaction}) { +function MoneyRequestView({betas, report, parentReport, policyCategories, shouldShowHorizontalRule, transaction}) { const {isSmallScreenWidth} = useWindowDimensions(); const {translate} = useLocalize(); @@ -80,7 +85,10 @@ function MoneyRequestView({report, parentReport, policyCategories, shouldShowHor const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID); const canEdit = ReportUtils.canEditMoneyRequest(parentReportAction); - const shouldShowCategory = !_.isEmpty(policyCategories) || !_.isEmpty(transactionCategory); + // A flag for verifying that the current report is a sub-report of a workspace chat + const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)), [report]); + // A flag for showing categories + const shouldShowCategory = isPolicyExpenseChat && Permissions.canUseCategories(betas) && (!_.isEmpty(policyCategories) || !_.isEmpty(transactionCategory)); let description = `${translate('iou.amount')} • ${translate('iou.cash')}`; if (isSettled) { @@ -201,6 +209,9 @@ MoneyRequestView.displayName = 'MoneyRequestView'; export default compose( withCurrentUserPersonalDetails, withOnyx({ + betas: { + key: ONYXKEYS.BETAS, + }, parentReport: { key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`, }, From f8b84a96161b61712069800d54da4312300ead1a Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 18 Sep 2023 18:21:04 +0200 Subject: [PATCH 11/23] improve options helpers --- src/libs/OptionsListUtils.js | 38 +++++++++++++- tests/unit/OptionsListUtilsTest.js | 84 ------------------------------ 2 files changed, 37 insertions(+), 85 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 8027a30b34a1..c38f99edac65 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -599,6 +599,32 @@ function isCurrentUser(userDetails) { return _.some(_.keys(loginList), (login) => login.toLowerCase() === userDetailsLogin.toLowerCase()); } +/** + * Calculates count of all enabled options + * + * @param {Object[]} options - an initial strings array + * @param {Boolean} options[].enabled - a flag to enable/disable option in a list + * @param {String} options[].name - a name of an option + * @returns {Boolean} + */ +function getEnabledCategoriesCount(options) { + return _.chain(options) + .filter((option) => Boolean(option.enabled)) + .value().length; +} + +/** + * Verifies that there is at least one enabled option + * + * @param {Object[]} options - an initial strings array + * @param {Boolean} options[].enabled - a flag to enable/disable option in a list + * @param {String} options[].name - a name of an option + * @returns {Boolean} + */ +function hasEnabledOptions(options) { + return _.some(options, (option) => Boolean(option.enabled)); +} + /** * Build the options for the category tree hierarchy via indents * @@ -612,6 +638,10 @@ function getCategoryOptionTree(options, isOneLine = false) { const optionCollection = {}; _.each(options, (option) => { + if (!option.enabled) { + return; + } + if (isOneLine) { if (_.has(optionCollection, option.name)) { return; @@ -662,7 +692,11 @@ function getCategoryOptionTree(options, isOneLine = false) { */ function getCategoryListSections(categories, recentlyUsedCategories, selectedOptions, searchInputValue, maxRecentReportsToShow) { const categorySections = []; - const categoriesValues = _.values(categories); + const categoriesValues = _.chain(categories) + .values() + .filter((category) => category.enabled) + .value(); + const numberOfCategories = _.size(categoriesValues); let indexOffset = 0; @@ -1342,6 +1376,8 @@ export { isSearchStringMatch, shouldOptionShowTooltip, getLastMessageTextForReport, + getEnabledCategoriesCount, + hasEnabledOptions, getCategoryOptionTree, formatMemberForList, }; diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index ef90c767175e..f10eecefaafd 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -687,13 +687,6 @@ describe('OptionsListUtils', () => { shouldShow: false, indexOffset: 0, data: [ - { - text: 'Taxi', - keyForList: 'Taxi', - searchText: 'Taxi', - tooltipText: 'Taxi', - isDisabled: true, - }, { text: 'Restaurant', keyForList: 'Restaurant', @@ -827,13 +820,6 @@ describe('OptionsListUtils', () => { shouldShow: true, indexOffset: 1, data: [ - { - text: 'Taxi', - keyForList: 'Taxi', - searchText: 'Taxi', - tooltipText: 'Taxi', - isDisabled: true, - }, { text: 'Restaurant', keyForList: 'Restaurant', @@ -848,13 +834,6 @@ describe('OptionsListUtils', () => { shouldShow: true, indexOffset: 3, data: [ - { - text: 'Taxi', - keyForList: 'Taxi', - searchText: 'Taxi', - tooltipText: 'Taxi', - isDisabled: true, - }, { text: 'Restaurant', keyForList: 'Restaurant', @@ -883,13 +862,6 @@ describe('OptionsListUtils', () => { tooltipText: 'Milk', isDisabled: false, }, - { - text: ' Vegetables', - keyForList: 'Vegetables', - searchText: 'Food: Vegetables', - tooltipText: 'Vegetables', - isDisabled: true, - }, { text: 'Cars', keyForList: 'Cars', @@ -904,13 +876,6 @@ describe('OptionsListUtils', () => { tooltipText: 'Audi', isDisabled: false, }, - { - text: ' BMW', - keyForList: 'BMW', - searchText: 'Cars: BMW', - tooltipText: 'BMW', - isDisabled: true, - }, { text: ' Mercedes-Benz', keyForList: 'Mercedes-Benz', @@ -939,13 +904,6 @@ describe('OptionsListUtils', () => { tooltipText: 'Breakfast', isDisabled: false, }, - { - text: ' Dinner', - keyForList: 'Dinner', - searchText: 'Travel: Meals: Dinner', - tooltipText: 'Dinner', - isDisabled: true, - }, { text: ' Lunch', keyForList: 'Lunch', @@ -983,13 +941,6 @@ describe('OptionsListUtils', () => { tooltipText: 'Food: Milk', isDisabled: false, }, - { - text: 'Food: Vegetables', - keyForList: 'Food: Vegetables', - searchText: 'Food: Vegetables', - tooltipText: 'Food: Vegetables', - isDisabled: true, - }, ], }, ]; @@ -1153,13 +1104,6 @@ describe('OptionsListUtils', () => { }, }; const result = [ - { - text: 'Taxi', - keyForList: 'Taxi', - searchText: 'Taxi', - tooltipText: 'Taxi', - isDisabled: true, - }, { text: 'Restaurant', keyForList: 'Restaurant', @@ -1188,13 +1132,6 @@ describe('OptionsListUtils', () => { tooltipText: 'Milk', isDisabled: false, }, - { - text: ' Vegetables', - keyForList: 'Vegetables', - searchText: 'Food: Vegetables', - tooltipText: 'Vegetables', - isDisabled: true, - }, { text: 'Cars', keyForList: 'Cars', @@ -1209,13 +1146,6 @@ describe('OptionsListUtils', () => { tooltipText: 'Audi', isDisabled: false, }, - { - text: ' BMW', - keyForList: 'BMW', - searchText: 'Cars: BMW', - tooltipText: 'BMW', - isDisabled: true, - }, { text: ' Mercedes-Benz', keyForList: 'Mercedes-Benz', @@ -1223,13 +1153,6 @@ describe('OptionsListUtils', () => { tooltipText: 'Mercedes-Benz', isDisabled: false, }, - { - text: 'Medical', - keyForList: 'Medical', - searchText: 'Medical', - tooltipText: 'Medical', - isDisabled: true, - }, { text: 'Travel', keyForList: 'Travel', @@ -1251,13 +1174,6 @@ describe('OptionsListUtils', () => { tooltipText: 'Breakfast', isDisabled: false, }, - { - text: ' Dinner', - keyForList: 'Dinner', - searchText: 'Travel: Meals: Dinner', - tooltipText: 'Dinner', - isDisabled: true, - }, { text: ' Lunch', keyForList: 'Lunch', From b12a93ed40c9d0eb03c8be2c15769123d66ae2c2 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 18 Sep 2023 18:21:18 +0200 Subject: [PATCH 12/23] check enabled categories --- src/components/CategoryPicker/index.js | 2 +- src/components/MoneyRequestConfirmationList.js | 2 +- src/components/ReportActionItem/MoneyRequestView.js | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/CategoryPicker/index.js b/src/components/CategoryPicker/index.js index 66ac0bf14d4a..da7b77ca193e 100644 --- a/src/components/CategoryPicker/index.js +++ b/src/components/CategoryPicker/index.js @@ -14,7 +14,7 @@ function CategoryPicker({selectedCategory, policyCategories, policyRecentlyUsedC const {translate} = useLocalize(); const [searchValue, setSearchValue] = useState(''); - const policyCategoriesCount = _.size(policyCategories); + const policyCategoriesCount = OptionsListUtils.getEnabledCategoriesCount(_.values(policyCategories)); const isCategoriesCountBelowThreshold = policyCategoriesCount < CONST.CATEGORY_LIST_THRESHOLD; const selectedOptions = useMemo(() => { diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index d72860e78a48..7ed5ba0e1f09 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -196,7 +196,7 @@ function MoneyRequestConfirmationList(props) { const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(ReportUtils.getReport(props.reportID))), [props.reportID]); // A flag for showing the categories field - const shouldShowCategories = isPolicyExpenseChat && Permissions.canUseCategories(props.betas) && !_.isEmpty(props.policyCategories); + const shouldShowCategories = isPolicyExpenseChat && Permissions.canUseCategories(props.betas) && OptionsListUtils.hasEnabledOptions(_.values(props.policyCategories)); // Fetches the first tag list of the policy const tagListKey = _.first(_.keys(props.policyTags)); diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 8232f8618f2c..be937a834c42 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -14,6 +14,7 @@ import Permissions from '../../libs/Permissions'; import MenuItemWithTopDescription from '../MenuItemWithTopDescription'; import styles from '../../styles/styles'; import * as ReportUtils from '../../libs/ReportUtils'; +import * as OptionsListUtils from '../../libs/OptionsListUtils'; import * as ReportActionsUtils from '../../libs/ReportActionsUtils'; import * as StyleUtils from '../../styles/StyleUtils'; import CONST from '../../CONST'; @@ -88,7 +89,8 @@ function MoneyRequestView({betas, report, parentReport, policyCategories, should // A flag for verifying that the current report is a sub-report of a workspace chat const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)), [report]); // A flag for showing categories - const shouldShowCategory = isPolicyExpenseChat && Permissions.canUseCategories(betas) && (!_.isEmpty(policyCategories) || !_.isEmpty(transactionCategory)); + const shouldShowCategory = + isPolicyExpenseChat && Permissions.canUseCategories(betas) && (!_.isEmpty(transactionCategory) || OptionsListUtils.hasEnabledOptions(_.values(policyCategories))); let description = `${translate('iou.amount')} • ${translate('iou.cash')}`; if (isSettled) { From 7a643bfdfca602541f070e8ea257e8c462e5808a Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 18 Sep 2023 18:45:44 +0200 Subject: [PATCH 13/23] fix billable condition --- src/components/MoneyRequestConfirmationList.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index da969dce1145..d60b2e5d44bf 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -204,8 +204,12 @@ function MoneyRequestConfirmationList(props) { const tagListKey = _.first(_.keys(props.policyTags)); const tagList = lodashGet(props.policyTags, [tagListKey, 'tags'], []); const tagListName = lodashGet(props.policyTags, [tagListKey, 'name'], ''); + const canUseTags = Permissions.canUseTags(props.betas); // A flag for showing the tags field - const shouldShowTags = isPolicyExpenseChat && Permissions.canUseTags(props.betas) && !_.isEmpty(tagList); + const shouldShowTags = isPolicyExpenseChat && canUseTags && !_.isEmpty(tagList); + + // A flag for showing the billable field + const shouldShowBillable = canUseTags && !lodashGet(props.policy, 'disabledFields.defaultBillable', true); const formattedAmount = CurrencyUtils.convertToDisplayString( shouldCalculateDistanceAmount ? DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate) : props.iouAmount, @@ -539,7 +543,7 @@ function MoneyRequestConfirmationList(props) { disabled={didConfirm || props.isReadOnly} /> )} - {canUseTags && !lodashGet(props.policy, 'disabledFields.defaultBillable', true) && ( + {shouldShowBillable && ( {translate('common.billable')} Date: Tue, 19 Sep 2023 11:29:48 +0200 Subject: [PATCH 14/23] sort prop types --- src/components/ReportActionItem/MoneyRequestView.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 97eb23f80eeb..386d8090d7c4 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -33,6 +33,10 @@ import OfflineWithFeedback from '../OfflineWithFeedback'; import categoryPropTypes from '../categoryPropTypes'; const propTypes = { + /** Whether we should display the horizontal rule below the component */ + shouldShowHorizontalRule: PropTypes.bool.isRequired, + + /* Onyx Props */ /** List of betas available to current user */ betas: PropTypes.arrayOf(PropTypes.string), @@ -42,16 +46,12 @@ const propTypes = { /** The expense report or iou report (only will have a value if this is a transaction thread) */ parentReport: iouReportPropTypes, - /* Onyx Props */ /** Collection of categories attached to a policy */ policyCategories: PropTypes.objectOf(categoryPropTypes), /** The transaction associated with the transactionThread */ transaction: transactionPropTypes, - /** Whether we should display the horizontal rule below the component */ - shouldShowHorizontalRule: PropTypes.bool.isRequired, - ...withCurrentUserPersonalDetailsPropTypes, }; From 4f875ea1641b11fa676b5bafbd3c0f3facd2d1fc Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 19 Sep 2023 11:37:24 +0200 Subject: [PATCH 15/23] simplify helpers --- src/libs/OptionsListUtils.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 5e44babe1083..ff318d4fd1e5 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -605,9 +605,7 @@ function isCurrentUser(userDetails) { * @returns {Boolean} */ function getEnabledCategoriesCount(options) { - return _.chain(options) - .filter((option) => Boolean(option.enabled)) - .value().length; + return _.filter(options, (option) => option.enabled).length; } /** @@ -619,7 +617,7 @@ function getEnabledCategoriesCount(options) { * @returns {Boolean} */ function hasEnabledOptions(options) { - return _.some(options, (option) => Boolean(option.enabled)); + return _.some(options, (option) => option.enabled); } /** From d962ce18928ab774f8f50e26a77c97f5d9e3b96e Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 19 Sep 2023 11:37:41 +0200 Subject: [PATCH 16/23] create a handler --- src/pages/EditRequestCategoryPage.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/pages/EditRequestCategoryPage.js b/src/pages/EditRequestCategoryPage.js index ba94c2b40800..b1ee6f3384f6 100644 --- a/src/pages/EditRequestCategoryPage.js +++ b/src/pages/EditRequestCategoryPage.js @@ -20,6 +20,12 @@ const propTypes = { function EditRequestCategoryPage({defaultCategory, policyID, onSubmit}) { const {translate} = useLocalize(); + const selectCategory = (category) => { + onSubmit({ + category: category.searchText, + }); + }; + return ( - onSubmit({ - category: category.searchText, - }) - } + onSubmit={selectCategory} /> ); From 72bd7e84f032a9c053adfba33a58e9b30ba710ed Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 19 Sep 2023 11:46:59 +0200 Subject: [PATCH 17/23] reuse iuo props --- src/pages/iou/MoneyRequestCategoryPage.js | 9 ++++----- src/pages/iou/propTypes/index.js | 4 ++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/pages/iou/MoneyRequestCategoryPage.js b/src/pages/iou/MoneyRequestCategoryPage.js index adba5755496d..92934a505a04 100644 --- a/src/pages/iou/MoneyRequestCategoryPage.js +++ b/src/pages/iou/MoneyRequestCategoryPage.js @@ -11,6 +11,7 @@ import CategoryPicker from '../../components/CategoryPicker'; import ONYXKEYS from '../../ONYXKEYS'; import reportPropTypes from '../reportPropTypes'; import * as IOU from '../../libs/actions/IOU'; +import {iouPropTypes, iouDefaultProps} from './propTypes'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -25,19 +26,17 @@ const propTypes = { }), }).isRequired, + /* Onyx Props */ /** The report currently being used */ report: reportPropTypes, - /* Onyx Props */ /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - iou: PropTypes.shape({ - category: PropTypes.string.isRequired, - }), + iou: iouPropTypes, }; const defaultProps = { report: {}, - iou: {}, + iou: iouDefaultProps, }; function MoneyRequestCategoryPage({route, report, iou}) { diff --git a/src/pages/iou/propTypes/index.js b/src/pages/iou/propTypes/index.js index 5ecd00d11876..586f8424a2c2 100644 --- a/src/pages/iou/propTypes/index.js +++ b/src/pages/iou/propTypes/index.js @@ -18,6 +18,9 @@ const iouPropTypes = PropTypes.shape({ /** The merchant name */ merchant: PropTypes.string, + /** The category name */ + category: PropTypes.string, + /** The tag */ tag: PropTypes.string, @@ -37,6 +40,7 @@ const iouDefaultProps = { currency: CONST.CURRENCY.USD, comment: '', merchant: '', + category: '', tag: '', created: '', participants: [], From 37d67702d350aaa6dca47ae274e8e4e1529562eb Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 19 Sep 2023 11:57:36 +0200 Subject: [PATCH 18/23] clarify props --- src/components/ReportActionItem/MoneyRequestView.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 386d8090d7c4..0aba850b2145 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -33,6 +33,9 @@ import OfflineWithFeedback from '../OfflineWithFeedback'; import categoryPropTypes from '../categoryPropTypes'; const propTypes = { + /** The report currently being looked at */ + report: reportPropTypes.isRequired, + /** Whether we should display the horizontal rule below the component */ shouldShowHorizontalRule: PropTypes.bool.isRequired, @@ -40,9 +43,6 @@ const propTypes = { /** List of betas available to current user */ betas: PropTypes.arrayOf(PropTypes.string), - /** The report currently being looked at */ - report: reportPropTypes.isRequired, - /** The expense report or iou report (only will have a value if this is a transaction thread) */ parentReport: iouReportPropTypes, From 3353869cc4725020a9205be609395b42ce7b0af9 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 19 Sep 2023 11:58:04 +0200 Subject: [PATCH 19/23] clarify return type --- src/libs/OptionsListUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index ff318d4fd1e5..6c17bad76dd5 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -602,7 +602,7 @@ function isCurrentUser(userDetails) { * @param {Object[]} options - an initial strings array * @param {Boolean} options[].enabled - a flag to enable/disable option in a list * @param {String} options[].name - a name of an option - * @returns {Boolean} + * @returns {Number} */ function getEnabledCategoriesCount(options) { return _.filter(options, (option) => option.enabled).length; From abd2d25dbdd9cf3e699a6d0d944e06e24dfc30f3 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 20 Sep 2023 11:43:50 +0200 Subject: [PATCH 20/23] re-test From 5cdc7fb71431e3d592999d49efba4e9beb43e462 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 20 Sep 2023 14:59:46 +0200 Subject: [PATCH 21/23] clarify comment --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 553cb0243f52..ed2e85a4ff11 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1649,7 +1649,7 @@ function getRootParentReport(report) { return {}; } - // Returns the founded root report, because it does not have a parentReportID + // Returns the current report as the root report, because it does not have a parentReportID if (!report.parentReportID) { return report; } From ce2907d21401cf6c713940e209d8539316e642f6 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 20 Sep 2023 15:06:46 +0200 Subject: [PATCH 22/23] perform conditions --- src/components/ReportActionItem/MoneyRequestView.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index d8ec67ae59da..178cab75a0c2 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -1,8 +1,8 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import lodashGet from 'lodash/get'; +import lodashValues from 'lodash/values'; import PropTypes from 'prop-types'; import reportPropTypes from '../../pages/reportPropTypes'; import ONYXKEYS from '../../ONYXKEYS'; @@ -90,8 +90,7 @@ function MoneyRequestView({betas, report, parentReport, policyCategories, should // A flag for verifying that the current report is a sub-report of a workspace chat const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)), [report]); // A flag for showing categories - const shouldShowCategory = - isPolicyExpenseChat && Permissions.canUseCategories(betas) && (!_.isEmpty(transactionCategory) || OptionsListUtils.hasEnabledOptions(_.values(policyCategories))); + const shouldShowCategory = isPolicyExpenseChat && Permissions.canUseCategories(betas) && (transactionCategory || OptionsListUtils.hasEnabledOptions(lodashValues(policyCategories))); let description = `${translate('iou.amount')} • ${translate('iou.cash')}`; if (isSettled) { From 8753fa362c0889c3356e58936cb3f89b6a64dbd1 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 21 Sep 2023 11:56:50 +0200 Subject: [PATCH 23/23] update name of a method --- tests/unit/OptionsListUtilsTest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index 6bc8b1b01528..6f20e48835fd 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -1024,7 +1024,7 @@ describe('OptionsListUtils', () => { ); expect(largeWrongSearchResult.categoryOptions).toStrictEqual(largeWrongSearchResultList); - const emptyResult = OptionsListUtils.getNewChatOptions(REPORTS, PERSONAL_DETAILS, [], search, selectedOptions, [], false, false, true, emptyCategoriesList); + const emptyResult = OptionsListUtils.getFilteredOptions(REPORTS, PERSONAL_DETAILS, [], search, selectedOptions, [], false, false, true, emptyCategoriesList); expect(emptyResult.categoryOptions).toStrictEqual(emptySelectedResultList); });