diff --git a/src/ROUTES.js b/src/ROUTES.js index 3f96d77d477e..6da2c5bf7ae9 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -92,6 +92,7 @@ export default { MONEY_REQUEST_DATE: ':iouType/new/date/:reportID?', MONEY_REQUEST_CURRENCY: ':iouType/new/currency/:reportID?', MONEY_REQUEST_DESCRIPTION: ':iouType/new/description/:reportID?', + MONEY_REQUEST_CATEGORY: ':iouType/new/category/:reportID?', MONEY_REQUEST_MERCHANT: ':iouType/new/merchant/:reportID?', MONEY_REQUEST_MANUAL_TAB: ':iouType/new/:reportID?/manual', MONEY_REQUEST_SCAN_TAB: ':iouType/new/:reportID?/scan', @@ -107,6 +108,7 @@ export default { getMoneyRequestCreatedRoute: (iouType, reportID = '') => `${iouType}/new/date/${reportID}`, getMoneyRequestCurrencyRoute: (iouType, reportID = '', currency, backTo) => `${iouType}/new/currency/${reportID}?currency=${currency}&backTo=${backTo}`, getMoneyRequestDescriptionRoute: (iouType, reportID = '') => `${iouType}/new/description/${reportID}`, + getMoneyRequestCategoryRoute: (iouType, reportID = '') => `${iouType}/new/category/${reportID}`, getMoneyRequestMerchantRoute: (iouType, reportID = '') => `${iouType}/new/merchant/${reportID}`, getMoneyRequestDistanceTabRoute: (iouType, reportID = '') => `${iouType}/new/${reportID}/distance`, getMoneyRequestWaypointRoute: (iouType, waypointIndex) => `${iouType}/new/waypoint/${waypointIndex}`, diff --git a/src/components/CategoryPicker/categoryPickerPropTypes.js b/src/components/CategoryPicker/categoryPickerPropTypes.js new file mode 100644 index 000000000000..ccc1643021ce --- /dev/null +++ b/src/components/CategoryPicker/categoryPickerPropTypes.js @@ -0,0 +1,24 @@ +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, + + /* Onyx Props */ + /** Collection of categories attached to a policy */ + policyCategories: PropTypes.objectOf(categoryPropTypes), +}; + +const defaultProps = { + policyID: '', + policyCategories: null, +}; + +export {propTypes, defaultProps}; diff --git a/src/components/CategoryPicker/index.js b/src/components/CategoryPicker/index.js new file mode 100644 index 000000000000..163ab6673ca2 --- /dev/null +++ b/src/components/CategoryPicker/index.js @@ -0,0 +1,56 @@ +import React, {useMemo} from 'react'; +import _ from 'underscore'; +import {withOnyx} from 'react-native-onyx'; +import ONYXKEYS from '../../ONYXKEYS'; +import {propTypes, defaultProps} from './categoryPickerPropTypes'; +import OptionsList from '../OptionsList'; +import styles from '../../styles/styles'; +import ScreenWrapper from '../ScreenWrapper'; +import Navigation from '../../libs/Navigation/Navigation'; +import ROUTES from '../../ROUTES'; + +function CategoryPicker({policyCategories, reportID, iouType}) { + const sections = useMemo(() => { + const categoryList = _.chain(policyCategories) + .values() + .map((category) => ({ + text: category.name, + keyForList: category.name, + tooltipText: category.name, + })) + .value(); + + return [ + { + data: categoryList, + }, + ]; + }, [policyCategories]); + + const navigateBack = () => { + Navigation.goBack(ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID)); + }; + + return ( + + {({safeAreaPaddingBottomStyle}) => ( + + )} + + ); +} + +CategoryPicker.displayName = 'CategoryPicker'; +CategoryPicker.propTypes = propTypes; +CategoryPicker.defaultProps = defaultProps; + +export default withOnyx({ + policyCategories: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, + }, +})(CategoryPicker); diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index ffd65cfb8f74..3dc7f06acfad 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -27,6 +27,7 @@ import themeColors from '../styles/themes/default'; import Image from './Image'; import useLocalize from '../hooks/useLocalize'; import * as ReceiptUtils from '../libs/ReceiptUtils'; +import categoryPropTypes from './categoryPropTypes'; const propTypes = { /** Callback to inform parent modal of success */ @@ -59,6 +60,9 @@ const propTypes = { /** IOU merchant */ iouMerchant: PropTypes.string, + /** IOU Category */ + iouCategory: PropTypes.string, + /** Selected participants from MoneyRequestModal with login / accountID */ selectedParticipants: PropTypes.arrayOf(optionPropTypes).isRequired, @@ -92,6 +96,10 @@ const propTypes = { /** File source of the receipt */ receiptSource: PropTypes.string, + + /* Onyx Props */ + /** Collection of categories attached to a policy */ + policyCategories: PropTypes.objectOf(categoryPropTypes), }; const defaultProps = { @@ -99,6 +107,7 @@ const defaultProps = { onSendMoney: () => {}, onSelectParticipant: () => {}, iouType: CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, + iouCategory: '', payeePersonalDetails: null, canModifyParticipants: false, isReadOnly: false, @@ -111,6 +120,7 @@ const defaultProps = { ...withCurrentUserPersonalDetailsDefaultProps, receiptPath: '', receiptSource: '', + policyCategories: {}, }; function MoneyRequestConfirmationList(props) { @@ -393,6 +403,16 @@ function MoneyRequestConfirmationList(props) { onPress={() => Navigation.navigate(ROUTES.getMoneyRequestMerchantRoute(props.iouType, props.reportID))} disabled={didConfirm || props.isReadOnly || !isTypeRequest} /> + {!_.isEmpty(props.policyCategories) && ( + Navigation.navigate(ROUTES.getMoneyRequestCategoryRoute(props.iouType, props.reportID))} + style={[styles.moneyRequestMenuItem, styles.mb2]} + disabled={didConfirm || props.isReadOnly} + /> + )} )} @@ -408,5 +428,8 @@ export default compose( session: { key: ONYXKEYS.SESSION, }, + policyCategories: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`, + }, }), )(MoneyRequestConfirmationList); diff --git a/src/components/categoryPropTypes.js b/src/components/categoryPropTypes.js new file mode 100644 index 000000000000..90c3ac368d1c --- /dev/null +++ b/src/components/categoryPropTypes.js @@ -0,0 +1,9 @@ +import PropTypes from 'prop-types'; + +export default PropTypes.shape({ + /** Name of a category */ + name: PropTypes.string.isRequired, + + /** Flag that determines if a category is active and able to be selected */ + enabled: PropTypes.bool.isRequired, +}); diff --git a/src/languages/en.js b/src/languages/en.js index d0c945fbc37d..477564053939 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -155,6 +155,7 @@ export default { edit: 'Edit', showMore: 'Show more', merchant: 'Merchant', + category: 'Category', receipt: 'Receipt', replace: 'Replace', }, diff --git a/src/languages/es.js b/src/languages/es.js index 7f7457f686b8..4852c23326cb 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -154,6 +154,7 @@ export default { edit: 'Editar', showMore: 'Mostrar más', merchant: 'Comerciante', + category: 'Categoría', receipt: 'Recibo', replace: 'Sustituir', }, diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index aa4fcc02c906..d172911d68ed 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -83,6 +83,13 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator([ }, name: 'Money_Request_Description', }, + { + getComponent: () => { + const MoneyRequestCategoryPage = require('../../../pages/iou/MoneyRequestCategoryPage').default; + return MoneyRequestCategoryPage; + }, + name: 'Money_Request_Category', + }, { getComponent: () => { const MoneyRequestMerchantPage = require('../../../pages/iou/MoneyRequestMerchantPage').default; diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index a76ebbf776da..ebea00d4b05b 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -310,6 +310,7 @@ export default { Money_Request_Date: ROUTES.MONEY_REQUEST_DATE, Money_Request_Currency: ROUTES.MONEY_REQUEST_CURRENCY, Money_Request_Description: ROUTES.MONEY_REQUEST_DESCRIPTION, + Money_Request_Category: ROUTES.MONEY_REQUEST_CATEGORY, Money_Request_Merchant: ROUTES.MONEY_REQUEST_MERCHANT, Money_Request_Waypoint: ROUTES.MONEY_REQUEST_WAYPOINT, IOU_Send_Enable_Payments: ROUTES.IOU_SEND_ENABLE_PAYMENTS, diff --git a/src/pages/iou/MoneyRequestCategoryPage.js b/src/pages/iou/MoneyRequestCategoryPage.js new file mode 100644 index 000000000000..80b88a762609 --- /dev/null +++ b/src/pages/iou/MoneyRequestCategoryPage.js @@ -0,0 +1,72 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import lodashGet from 'lodash/get'; +import {withOnyx} from 'react-native-onyx'; +import ROUTES from '../../ROUTES'; +import Navigation from '../../libs/Navigation/Navigation'; +import useLocalize from '../../hooks/useLocalize'; +import ScreenWrapper from '../../components/ScreenWrapper'; +import HeaderWithBackButton from '../../components/HeaderWithBackButton'; +import CategoryPicker from '../../components/CategoryPicker'; +import ONYXKEYS from '../../ONYXKEYS'; +import reportPropTypes from '../reportPropTypes'; + +const propTypes = { + /** Navigation route context info provided by react navigation */ + route: PropTypes.shape({ + /** Route specific parameters used on this screen via route :iouType/new/category/:reportID? */ + params: PropTypes.shape({ + /** The type of IOU report, i.e. bill, request, send */ + iouType: PropTypes.string, + + /** The report ID of the IOU */ + reportID: PropTypes.string, + }), + }).isRequired, + + /** The report currently being used */ + report: reportPropTypes, +}; + +const defaultProps = { + report: {}, +}; + +function MoneyRequestCategoryPage({route, report}) { + const {translate} = useLocalize(); + + const reportID = lodashGet(route, 'params.reportID', ''); + const iouType = lodashGet(route, 'params.iouType', ''); + + const navigateBack = () => { + Navigation.goBack(ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID)); + }; + + return ( + + + + + + ); +} + +MoneyRequestCategoryPage.displayName = 'MoneyRequestCategoryPage'; +MoneyRequestCategoryPage.propTypes = propTypes; +MoneyRequestCategoryPage.defaultProps = defaultProps; + +export default withOnyx({ + report: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${lodashGet(route, 'params.reportID', '')}`, + }, +})(MoneyRequestCategoryPage);