From 0479a7eced2c7bb86a2ca330fb5604f6e8dbdd56 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 5 Sep 2023 08:30:29 +0530 Subject: [PATCH 01/48] Implement dedicated route for CountryPicker in AddressPage --- src/ROUTES.js | 9 ++ .../AppNavigator/ModalStackNavigators.js | 7 ++ src/libs/Navigation/linkingConfig.js | 4 + .../Profile/PersonalDetails/AddressPage.js | 68 ++++++++++-- .../PersonalDetails/CountrySelection.js | 102 ++++++++++++++++++ 5 files changed, 182 insertions(+), 8 deletions(-) create mode 100644 src/pages/settings/Profile/PersonalDetails/CountrySelection.js diff --git a/src/ROUTES.js b/src/ROUTES.js index b38ce25f590f..d8a451c6416f 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -54,6 +54,15 @@ export default { SETTINGS_PERSONAL_DETAILS_LEGAL_NAME: `${SETTINGS_PERSONAL_DETAILS}/legal-name`, SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH: `${SETTINGS_PERSONAL_DETAILS}/date-of-birth`, SETTINGS_PERSONAL_DETAILS_ADDRESS: `${SETTINGS_PERSONAL_DETAILS}/address`, + getPersonalDetailsAddressRoute: (country) => `${SETTINGS_PERSONAL_DETAILS}/address?country=${country}`, + SETTINGS_PERSONAL_DETAILS_ADDRESS_COUNTRY: `${SETTINGS_PERSONAL_DETAILS}/address/country`, + getCountryRoute: (country, backTo) => { + let route = `${SETTINGS_PERSONAL_DETAILS}/address/country?country=${country}`; + if (backTo) { + route += `&backTo=${backTo}`; + } + return route; + }, SETTINGS_CONTACT_METHODS, SETTINGS_CONTACT_METHOD_DETAILS: `${SETTINGS_CONTACT_METHODS}/:contactMethod/details`, getEditContactMethodRoute: (contactMethod) => `${SETTINGS_CONTACT_METHODS}/${encodeURIComponent(contactMethod)}/details`, diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 2adaf0397a2c..fa4b5f9587f9 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -440,6 +440,13 @@ const SettingsModalStackNavigator = createModalStackNavigator([ }, name: 'Settings_PersonalDetails_Address', }, + { + getComponent: () => { + const CountrySelectionPage = require('../../../pages/settings/Profile/PersonalDetails/CountrySelection').default; + return CountrySelectionPage; + }, + name: 'Settings_PersonalDetails_Address_Country', + }, { getComponent: () => { const SettingsContactMethodsPage = require('../../../pages/settings/Profile/Contacts/ContactMethodsPage').default; diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 8390aa7d700b..edfe29043cb2 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -153,6 +153,10 @@ export default { path: ROUTES.SETTINGS_PERSONAL_DETAILS_ADDRESS, exact: true, }, + Settings_PersonalDetails_Address_Country: { + path: ROUTES.SETTINGS_PERSONAL_DETAILS_ADDRESS_COUNTRY, + exact: true, + }, Settings_TwoFactorAuth: { path: ROUTES.SETTINGS_2FA, exact: true, diff --git a/src/pages/settings/Profile/PersonalDetails/AddressPage.js b/src/pages/settings/Profile/PersonalDetails/AddressPage.js index b26c833aee11..360cdcdc5672 100644 --- a/src/pages/settings/Profile/PersonalDetails/AddressPage.js +++ b/src/pages/settings/Profile/PersonalDetails/AddressPage.js @@ -1,6 +1,6 @@ import lodashGet from 'lodash/get'; import _ from 'underscore'; -import React, {useState, useCallback} from 'react'; +import React, {useState, useCallback, useEffect, forwardRef} from 'react'; import PropTypes from 'prop-types'; import {View} from 'react-native'; import {CONST as COMMON_CONST} from 'expensify-common/lib/CONST'; @@ -15,13 +15,14 @@ import styles from '../../../../styles/styles'; import * as PersonalDetails from '../../../../libs/actions/PersonalDetails'; import * as ValidationUtils from '../../../../libs/ValidationUtils'; import AddressSearch from '../../../../components/AddressSearch'; -import CountryPicker from '../../../../components/CountryPicker'; import StatePicker from '../../../../components/StatePicker'; import Navigation from '../../../../libs/Navigation/Navigation'; import ROUTES from '../../../../ROUTES'; import useLocalize from '../../../../hooks/useLocalize'; import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails'; import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator'; +import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription'; +import FormHelpMessage from '../../../../components/FormHelpMessage'; const propTypes = { /* Onyx Props */ @@ -37,6 +38,14 @@ const propTypes = { country: PropTypes.string, }), }), + /** Route from navigation */ + route: PropTypes.shape({ + /** Params from the route */ + params: PropTypes.shape({ + /** Currently selected currency */ + country: PropTypes.string, + }), + }).isRequired, }; const defaultProps = { @@ -59,10 +68,11 @@ function updateAddress(values) { PersonalDetails.updateAddress(values.addressLine1.trim(), values.addressLine2.trim(), values.city.trim(), values.state.trim(), values.zipPostCode.trim().toUpperCase(), values.country); } -function AddressPage({privatePersonalDetails}) { +function AddressPage({privatePersonalDetails, route}) { usePrivatePersonalDetails(); const {translate} = useLocalize(); - const [currentCountry, setCurrentCountry] = useState(PersonalDetails.getCountryISO(lodashGet(privatePersonalDetails, 'address.country'))); + const countryFromUrl = lodashGet(route, 'params.country'); + const [currentCountry, setCurrentCountry] = useState(countryFromUrl || PersonalDetails.getCountryISO(lodashGet(privatePersonalDetails, 'address.country'))); const isUSAForm = currentCountry === CONST.COUNTRY.US; const zipSampleFormat = lodashGet(CONST.COUNTRY_ZIP_REGEX_DATA, [currentCountry, 'samples'], ''); const zipFormat = translate('common.zipCodeExampleFormat', {zipSampleFormat}); @@ -115,7 +125,7 @@ function AddressPage({privatePersonalDetails}) { return errors; }, []); - const handleAddressChange = (value, key) => { + const handleAddressChange = useCallback((value, key) => { if (key !== 'country' && key !== 'state') { return; } @@ -125,7 +135,12 @@ function AddressPage({privatePersonalDetails}) { return; } setState(value); - }; + }, []); + + useEffect(() => { + if (!countryFromUrl) return; + handleAddressChange(countryFromUrl, 'country'); + }, [countryFromUrl, handleAddressChange]); if (lodashGet(privatePersonalDetails, 'isLoading', true)) { return ; @@ -177,8 +192,7 @@ function AddressPage({privatePersonalDetails}) { @@ -236,3 +250,41 @@ export default withOnyx({ key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS, }, })(AddressPage); + +const CountryPicker = React.memo( + forwardRef(({errorText, value}, ref) => { + const {translate} = useLocalize(); + const getCountryFromCountryCode = (code) => translate('allCountries')[code]; + + const countryTitleDescStyle = value && value.length === 0 ? styles.textNormal : null; + + return ( + + { + const activeRoute = Navigation.getActiveRoute().replace(/\?.*/, ''); + Navigation.navigate(ROUTES.getCountryRoute(value, activeRoute)); + }} + /> + + + + + ); + }), +); + +CountryPicker.propTypes = { + errorText: PropTypes.string, + value: PropTypes.string, +}; + +CountryPicker.defaultProps = { + errorText: '', + value: '', +}; diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js new file mode 100644 index 000000000000..69d7f347b08c --- /dev/null +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js @@ -0,0 +1,102 @@ +import React, {useState, useMemo, useCallback} from 'react'; +import PropTypes from 'prop-types'; +import _ from 'underscore'; +import lodashGet from 'lodash/get'; +import Navigation from '../../../../libs/Navigation/Navigation'; +import ScreenWrapper from '../../../../components/ScreenWrapper'; +import HeaderWithBackButton from '../../../../components/HeaderWithBackButton'; +import compose from '../../../../libs/compose'; +import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize'; +import {withNetwork} from '../../../../components/OnyxProvider'; +import SelectionList from '../../../../components/SelectionList'; +import searchCountryOptions from '../../../../libs/searchCountryOptions'; +import StringUtils from '../../../../libs/StringUtils'; + +import useLocalize from '../../../../hooks/useLocalize'; + +/** + * IOU Currency selection for selecting currency + */ +const propTypes = { + /** Route from navigation */ + route: PropTypes.shape({ + /** Params from the route */ + params: PropTypes.shape({ + /** Currently selected country */ + country: PropTypes.string, + + /** Route to navigate back after selecting a currency */ + backTo: PropTypes.string, + }), + }).isRequired, + + ...withLocalizePropTypes, +}; + +const defaultProps = {}; + +function CountrySelection(props) { + const [searchValue, setSearchValue] = useState(''); + const {translate} = useLocalize(); + const currentCountry = lodashGet(props, 'route.params.country'); + + const countries = useMemo( + () => + _.map(translate('allCountries'), (countryName, countryISO) => ({ + value: countryISO, + keyForList: countryISO, + text: countryName, + isSelected: currentCountry === countryISO, + searchValue: StringUtils.sanitizeString(`${countryISO}${countryName}`), + })), + [translate, currentCountry], + ); + + const searchResults = searchCountryOptions(searchValue, countries); + const headerMessage = searchValue.trim() && !searchResults.length ? translate('common.noResultsFound') : ''; + + const selectCountry = useCallback( + (option) => { + const currentCountryInner = option.value; + const backTo = lodashGet(props.route, 'params.backTo', ''); + const backToRoute = backTo ? `${backTo}?country=${currentCountryInner}` : ''; + Navigation.goBack(backToRoute, true); + }, + [props.route], + ); + + return ( + + { + const backTo = lodashGet(props.route, 'params.backTo', ''); + const backToRoute = backTo ? `${backTo}?country=${currentCountry}` : ''; + Navigation.goBack(backToRoute); + }} + /> + + + + ); +} + +CountrySelection.displayName = 'CountrySelection'; +CountrySelection.propTypes = propTypes; +CountrySelection.defaultProps = defaultProps; + +export default compose( + withLocalize, + + withNetwork(), +)(CountrySelection); From b5a0ebc4050493536844b4823d8d48252514377a Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt <65986357+ygshbht@users.noreply.github.com> Date: Wed, 6 Sep 2023 05:22:13 +0530 Subject: [PATCH 02/48] Comment correction Co-authored-by: Rajat Parashar --- src/pages/settings/Profile/PersonalDetails/CountrySelection.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js index 69d7f347b08c..8723440436d9 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js @@ -14,9 +14,6 @@ import StringUtils from '../../../../libs/StringUtils'; import useLocalize from '../../../../hooks/useLocalize'; -/** - * IOU Currency selection for selecting currency - */ const propTypes = { /** Route from navigation */ route: PropTypes.shape({ From 3cbd8d2aeac626300a01b88defa270ba6decd844 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Wed, 6 Sep 2023 05:33:01 +0530 Subject: [PATCH 03/48] Remove unused dependencies in CountrySelection --- .../Profile/PersonalDetails/CountrySelection.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js index 8723440436d9..7b1f2d11960e 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js @@ -5,9 +5,6 @@ import lodashGet from 'lodash/get'; import Navigation from '../../../../libs/Navigation/Navigation'; import ScreenWrapper from '../../../../components/ScreenWrapper'; import HeaderWithBackButton from '../../../../components/HeaderWithBackButton'; -import compose from '../../../../libs/compose'; -import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize'; -import {withNetwork} from '../../../../components/OnyxProvider'; import SelectionList from '../../../../components/SelectionList'; import searchCountryOptions from '../../../../libs/searchCountryOptions'; import StringUtils from '../../../../libs/StringUtils'; @@ -26,8 +23,6 @@ const propTypes = { backTo: PropTypes.string, }), }).isRequired, - - ...withLocalizePropTypes, }; const defaultProps = {}; @@ -92,8 +87,4 @@ CountrySelection.displayName = 'CountrySelection'; CountrySelection.propTypes = propTypes; CountrySelection.defaultProps = defaultProps; -export default compose( - withLocalize, - - withNetwork(), -)(CountrySelection); +export default CountrySelection; From 53286fdb7c4b787ab962784fd450e492869e24eb Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Wed, 6 Sep 2023 05:34:56 +0530 Subject: [PATCH 04/48] CountrySelection refactoring --- .../Profile/PersonalDetails/CountrySelection.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js index 7b1f2d11960e..870f4b9f5253 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js @@ -27,10 +27,10 @@ const propTypes = { const defaultProps = {}; -function CountrySelection(props) { +function CountrySelection({route}) { const [searchValue, setSearchValue] = useState(''); const {translate} = useLocalize(); - const currentCountry = lodashGet(props, 'route.params.country'); + const currentCountry = lodashGet(route, 'params.country'); const countries = useMemo( () => @@ -50,11 +50,11 @@ function CountrySelection(props) { const selectCountry = useCallback( (option) => { const currentCountryInner = option.value; - const backTo = lodashGet(props.route, 'params.backTo', ''); + const backTo = lodashGet(route, 'params.backTo', ''); const backToRoute = backTo ? `${backTo}?country=${currentCountryInner}` : ''; Navigation.goBack(backToRoute, true); }, - [props.route], + [route], ); return ( @@ -63,7 +63,7 @@ function CountrySelection(props) { title={translate('common.country')} shouldShowBackButton onBackButtonPress={() => { - const backTo = lodashGet(props.route, 'params.backTo', ''); + const backTo = lodashGet(route, 'params.backTo', ''); const backToRoute = backTo ? `${backTo}?country=${currentCountry}` : ''; Navigation.goBack(backToRoute); }} From d88cc417995580a750b30e295da0dbefed748d16 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Wed, 6 Sep 2023 05:35:46 +0530 Subject: [PATCH 05/48] CountrySelection remove defaultProps --- src/pages/settings/Profile/PersonalDetails/CountrySelection.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js index 870f4b9f5253..b72ef41943f1 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js @@ -25,8 +25,6 @@ const propTypes = { }).isRequired, }; -const defaultProps = {}; - function CountrySelection({route}) { const [searchValue, setSearchValue] = useState(''); const {translate} = useLocalize(); @@ -85,6 +83,5 @@ function CountrySelection({route}) { CountrySelection.displayName = 'CountrySelection'; CountrySelection.propTypes = propTypes; -CountrySelection.defaultProps = defaultProps; export default CountrySelection; From b8cacd76ed1acfbdd45aaf51694d79c12b39874f Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Wed, 6 Sep 2023 05:57:15 +0530 Subject: [PATCH 06/48] Make CountryPickerMenuItem a new component on its own page --- src/components/CountryPickerMenuItem.js | 50 +++++++++++++++++++ .../Profile/PersonalDetails/AddressPage.js | 45 ++--------------- 2 files changed, 53 insertions(+), 42 deletions(-) create mode 100644 src/components/CountryPickerMenuItem.js diff --git a/src/components/CountryPickerMenuItem.js b/src/components/CountryPickerMenuItem.js new file mode 100644 index 000000000000..3ecfa0345a6a --- /dev/null +++ b/src/components/CountryPickerMenuItem.js @@ -0,0 +1,50 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import {View} from 'react-native'; +import styles from '../styles/styles'; +import Navigation from '../libs/Navigation/Navigation'; +import ROUTES from '../ROUTES'; +import useLocalize from '../hooks/useLocalize'; +import MenuItemWithTopDescription from './MenuItemWithTopDescription'; +import FormHelpMessage from './FormHelpMessage'; + +const propTypes = { + errorText: PropTypes.string, + value: PropTypes.string, +}; + +const defaultProps = { + errorText: '', + value: '', +}; + +function CountryPickerMenuItem({errorText, value}, ref) { + const {translate} = useLocalize(); + const getCountryFromCountryCode = (code) => translate('allCountries')[code]; + + const countryTitleDescStyle = value && value.length === 0 ? styles.textNormal : null; + + return ( + + { + const activeRoute = Navigation.getActiveRoute().replace(/\?.*/, ''); + Navigation.navigate(ROUTES.getCountryRoute(value, activeRoute)); + }} + /> + + + + + ); +} + +CountryPickerMenuItem.propTypes = propTypes; +CountryPickerMenuItem.defaultProps = defaultProps; + +export default React.memo(React.forwardRef(CountryPickerMenuItem)); diff --git a/src/pages/settings/Profile/PersonalDetails/AddressPage.js b/src/pages/settings/Profile/PersonalDetails/AddressPage.js index 360cdcdc5672..89241ba4b4bb 100644 --- a/src/pages/settings/Profile/PersonalDetails/AddressPage.js +++ b/src/pages/settings/Profile/PersonalDetails/AddressPage.js @@ -1,6 +1,6 @@ import lodashGet from 'lodash/get'; import _ from 'underscore'; -import React, {useState, useCallback, useEffect, forwardRef} from 'react'; +import React, {useState, useCallback, useEffect} from 'react'; import PropTypes from 'prop-types'; import {View} from 'react-native'; import {CONST as COMMON_CONST} from 'expensify-common/lib/CONST'; @@ -21,8 +21,7 @@ import ROUTES from '../../../../ROUTES'; import useLocalize from '../../../../hooks/useLocalize'; import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails'; import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator'; -import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription'; -import FormHelpMessage from '../../../../components/FormHelpMessage'; +import CountryPickerMenuItem from '../../../../components/CountryPickerMenuItem'; const propTypes = { /* Onyx Props */ @@ -190,7 +189,7 @@ function AddressPage({privatePersonalDetails, route}) { /> - @@ -250,41 +249,3 @@ export default withOnyx({ key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS, }, })(AddressPage); - -const CountryPicker = React.memo( - forwardRef(({errorText, value}, ref) => { - const {translate} = useLocalize(); - const getCountryFromCountryCode = (code) => translate('allCountries')[code]; - - const countryTitleDescStyle = value && value.length === 0 ? styles.textNormal : null; - - return ( - - { - const activeRoute = Navigation.getActiveRoute().replace(/\?.*/, ''); - Navigation.navigate(ROUTES.getCountryRoute(value, activeRoute)); - }} - /> - - - - - ); - }), -); - -CountryPicker.propTypes = { - errorText: PropTypes.string, - value: PropTypes.string, -}; - -CountryPicker.defaultProps = { - errorText: '', - value: '', -}; From f4ae5b223a0ff72ba3e969facf91238204b14c92 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Wed, 6 Sep 2023 08:56:27 +0530 Subject: [PATCH 07/48] CountrySelection Navigation bugfix after selecting country --- .../PersonalDetails/CountrySelection.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js index b72ef41943f1..4ef61ea4c784 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js @@ -23,9 +23,12 @@ const propTypes = { backTo: PropTypes.string, }), }).isRequired, + navigation: PropTypes.shape({ + getState: PropTypes.func.isRequired, + }).isRequired, }; -function CountrySelection({route}) { +function CountrySelection({route, navigation}) { const [searchValue, setSearchValue] = useState(''); const {translate} = useLocalize(); const currentCountry = lodashGet(route, 'params.country'); @@ -47,12 +50,17 @@ function CountrySelection({route}) { const selectCountry = useCallback( (option) => { - const currentCountryInner = option.value; const backTo = lodashGet(route, 'params.backTo', ''); - const backToRoute = backTo ? `${backTo}?country=${currentCountryInner}` : ''; - Navigation.goBack(backToRoute, true); + + if (navigation.getState().routes.length === 1 && _.isEmpty(backTo)) { + Navigation.goBack(); + } else if (!_.isEmpty(backTo) && navigation.getState().routes.length === 1) { + Navigation.goBack(`${route.params.backTo}?country=${option.value}`); + } else { + Navigation.navigate(`${route.params.backTo}?country=${option.value}`); + } }, - [route], + [route, navigation], ); return ( From ae6ebcf4b2be5f7c662e9973a7eb13bbc43032c5 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Wed, 6 Sep 2023 19:28:01 +0530 Subject: [PATCH 08/48] Delete Old CountryPicker Modal --- .../CountryPicker/CountrySelectorModal.js | 102 ------------------ src/components/CountryPicker/index.js | 89 --------------- 2 files changed, 191 deletions(-) delete mode 100644 src/components/CountryPicker/CountrySelectorModal.js delete mode 100644 src/components/CountryPicker/index.js diff --git a/src/components/CountryPicker/CountrySelectorModal.js b/src/components/CountryPicker/CountrySelectorModal.js deleted file mode 100644 index 126cea7e842e..000000000000 --- a/src/components/CountryPicker/CountrySelectorModal.js +++ /dev/null @@ -1,102 +0,0 @@ -import _ from 'underscore'; -import React, {useMemo, useEffect} from 'react'; -import PropTypes from 'prop-types'; -import CONST from '../../CONST'; -import useLocalize from '../../hooks/useLocalize'; -import HeaderWithBackButton from '../HeaderWithBackButton'; -import SelectionList from '../SelectionList'; -import Modal from '../Modal'; -import ScreenWrapper from '../ScreenWrapper'; -import styles from '../../styles/styles'; -import searchCountryOptions from '../../libs/searchCountryOptions'; -import StringUtils from '../../libs/StringUtils'; - -const propTypes = { - /** Whether the modal is visible */ - isVisible: PropTypes.bool.isRequired, - - /** Country value selected */ - currentCountry: PropTypes.string, - - /** Function to call when the user selects a Country */ - onCountrySelected: PropTypes.func, - - /** Function to call when the user closes the Country modal */ - onClose: PropTypes.func, - - /** The search value from the selection list */ - searchValue: PropTypes.string.isRequired, - - /** Function to call when the user types in the search input */ - setSearchValue: PropTypes.func.isRequired, -}; - -const defaultProps = { - currentCountry: '', - onClose: () => {}, - onCountrySelected: () => {}, -}; - -function CountrySelectorModal({currentCountry, isVisible, onClose, onCountrySelected, setSearchValue, searchValue}) { - const {translate} = useLocalize(); - - useEffect(() => { - if (isVisible) { - return; - } - setSearchValue(''); - }, [isVisible, setSearchValue]); - - const countries = useMemo( - () => - _.map(translate('allCountries'), (countryName, countryISO) => ({ - value: countryISO, - keyForList: countryISO, - text: countryName, - isSelected: currentCountry === countryISO, - searchValue: StringUtils.sanitizeString(`${countryISO}${countryName}`), - })), - [translate, currentCountry], - ); - - const searchResults = searchCountryOptions(searchValue, countries); - const headerMessage = searchValue.trim() && !searchResults.length ? translate('common.noResultsFound') : ''; - - return ( - - - - - - - ); -} - -CountrySelectorModal.propTypes = propTypes; -CountrySelectorModal.defaultProps = defaultProps; -CountrySelectorModal.displayName = 'CountrySelectorModal'; - -export default CountrySelectorModal; diff --git a/src/components/CountryPicker/index.js b/src/components/CountryPicker/index.js deleted file mode 100644 index c6bbae0dd645..000000000000 --- a/src/components/CountryPicker/index.js +++ /dev/null @@ -1,89 +0,0 @@ -import React, {useState} from 'react'; -import {View} from 'react-native'; -import PropTypes from 'prop-types'; -import styles from '../../styles/styles'; -import MenuItemWithTopDescription from '../MenuItemWithTopDescription'; -import useLocalize from '../../hooks/useLocalize'; -import CountrySelectorModal from './CountrySelectorModal'; -import FormHelpMessage from '../FormHelpMessage'; -import refPropTypes from '../refPropTypes'; - -const propTypes = { - /** Form Error description */ - errorText: PropTypes.string, - - /** Country to display */ - value: PropTypes.string, - - /** Callback to call when the input changes */ - onInputChange: PropTypes.func, - - /** A ref to forward to MenuItemWithTopDescription */ - forwardedRef: refPropTypes, -}; - -const defaultProps = { - value: undefined, - forwardedRef: undefined, - errorText: '', - onInputChange: () => {}, -}; - -function CountryPicker({value, errorText, onInputChange, forwardedRef}) { - const {translate} = useLocalize(); - const allCountries = translate('allCountries'); - const [isPickerVisible, setIsPickerVisible] = useState(false); - const [searchValue, setSearchValue] = useState(''); - - const showPickerModal = () => { - setIsPickerVisible(true); - }; - - const hidePickerModal = () => { - setIsPickerVisible(false); - }; - - const updateCountryInput = (country) => { - onInputChange(country.value); - hidePickerModal(); - }; - - const title = allCountries[value] || ''; - const descStyle = title.length === 0 ? styles.textNormal : null; - - return ( - - - - - - - - ); -} - -CountryPicker.propTypes = propTypes; -CountryPicker.defaultProps = defaultProps; -CountryPicker.displayName = 'CountryPicker'; - -export default React.forwardRef((props, ref) => ( - -)); From 9cfcc96826c0a63cc566dada948f24d6084bbab3 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Wed, 6 Sep 2023 19:29:29 +0530 Subject: [PATCH 09/48] Add display name to CountryPickerMenuitem --- src/components/CountryPickerMenuItem.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/CountryPickerMenuItem.js b/src/components/CountryPickerMenuItem.js index 3ecfa0345a6a..abb0c485d594 100644 --- a/src/components/CountryPickerMenuItem.js +++ b/src/components/CountryPickerMenuItem.js @@ -46,5 +46,6 @@ function CountryPickerMenuItem({errorText, value}, ref) { CountryPickerMenuItem.propTypes = propTypes; CountryPickerMenuItem.defaultProps = defaultProps; +CountryPickerMenuItem.displayName = 'CountryPickerMenuItem'; export default React.memo(React.forwardRef(CountryPickerMenuItem)); From ff87483a8517cdf5f244d59f8b66022c8e5825a6 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt <65986357+ygshbht@users.noreply.github.com> Date: Thu, 7 Sep 2023 01:01:07 +0530 Subject: [PATCH 10/48] Remove memoing CountryPickerMenuItem Co-authored-by: Rajat Parashar --- src/components/CountryPickerMenuItem.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CountryPickerMenuItem.js b/src/components/CountryPickerMenuItem.js index 3ecfa0345a6a..8c9e60d0abb1 100644 --- a/src/components/CountryPickerMenuItem.js +++ b/src/components/CountryPickerMenuItem.js @@ -47,4 +47,4 @@ function CountryPickerMenuItem({errorText, value}, ref) { CountryPickerMenuItem.propTypes = propTypes; CountryPickerMenuItem.defaultProps = defaultProps; -export default React.memo(React.forwardRef(CountryPickerMenuItem)); +export default React.forwardRef(CountryPickerMenuItem); From f161188505c1cf5aad2643cb46f4ef600301cc5b Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Thu, 7 Sep 2023 01:08:14 +0530 Subject: [PATCH 11/48] Comment modifications to CountrySelection and related files --- src/components/CountryPickerMenuItem.js | 2 ++ src/pages/settings/Profile/PersonalDetails/AddressPage.js | 2 +- src/pages/settings/Profile/PersonalDetails/CountrySelection.js | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/CountryPickerMenuItem.js b/src/components/CountryPickerMenuItem.js index abb0c485d594..8aec6a21b35d 100644 --- a/src/components/CountryPickerMenuItem.js +++ b/src/components/CountryPickerMenuItem.js @@ -9,7 +9,9 @@ import MenuItemWithTopDescription from './MenuItemWithTopDescription'; import FormHelpMessage from './FormHelpMessage'; const propTypes = { + /** Error text from form, e.g when no country is selected */ errorText: PropTypes.string, + /** Current selected country */ value: PropTypes.string, }; diff --git a/src/pages/settings/Profile/PersonalDetails/AddressPage.js b/src/pages/settings/Profile/PersonalDetails/AddressPage.js index 89241ba4b4bb..cd25d1579264 100644 --- a/src/pages/settings/Profile/PersonalDetails/AddressPage.js +++ b/src/pages/settings/Profile/PersonalDetails/AddressPage.js @@ -41,7 +41,7 @@ const propTypes = { route: PropTypes.shape({ /** Params from the route */ params: PropTypes.shape({ - /** Currently selected currency */ + /** Currently selected country */ country: PropTypes.string, }), }).isRequired, diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js index 4ef61ea4c784..6c9cbbb677db 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js @@ -23,6 +23,7 @@ const propTypes = { backTo: PropTypes.string, }), }).isRequired, + /** Navigation from react-navigation */ navigation: PropTypes.shape({ getState: PropTypes.func.isRequired, }).isRequired, From ba351d1b1cd544e315fae33e49c95c7a6d45183c Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Thu, 7 Sep 2023 20:49:24 +0530 Subject: [PATCH 12/48] CountySelectionPage & related files refactoring and comments --- src/ROUTES.js | 3 +-- src/components/CountryPickerMenuItem.js | 11 ++++++----- .../Profile/PersonalDetails/CountrySelection.js | 5 +++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index d8a451c6416f..7c39991c7048 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -54,12 +54,11 @@ export default { SETTINGS_PERSONAL_DETAILS_LEGAL_NAME: `${SETTINGS_PERSONAL_DETAILS}/legal-name`, SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH: `${SETTINGS_PERSONAL_DETAILS}/date-of-birth`, SETTINGS_PERSONAL_DETAILS_ADDRESS: `${SETTINGS_PERSONAL_DETAILS}/address`, - getPersonalDetailsAddressRoute: (country) => `${SETTINGS_PERSONAL_DETAILS}/address?country=${country}`, SETTINGS_PERSONAL_DETAILS_ADDRESS_COUNTRY: `${SETTINGS_PERSONAL_DETAILS}/address/country`, getCountryRoute: (country, backTo) => { let route = `${SETTINGS_PERSONAL_DETAILS}/address/country?country=${country}`; if (backTo) { - route += `&backTo=${backTo}`; + route += `&backTo=${encodeURIComponent(backTo)}`; } return route; }, diff --git a/src/components/CountryPickerMenuItem.js b/src/components/CountryPickerMenuItem.js index 3c3f6f82aa4f..82b1ed0a449a 100644 --- a/src/components/CountryPickerMenuItem.js +++ b/src/components/CountryPickerMenuItem.js @@ -20,23 +20,24 @@ const defaultProps = { value: '', }; -function CountryPickerMenuItem({errorText, value}, ref) { +function CountryPickerMenuItem({errorText, value: countryCode}, ref) { const {translate} = useLocalize(); - const getCountryFromCountryCode = (code) => translate('allCountries')[code]; - const countryTitleDescStyle = value && value.length === 0 ? styles.textNormal : null; + const countries = translate('allCountries'); + const country = countries[countryCode] || ''; + const countryTitleDescStyle = country.length === 0 ? styles.textNormal : null; return ( { const activeRoute = Navigation.getActiveRoute().replace(/\?.*/, ''); - Navigation.navigate(ROUTES.getCountryRoute(value, activeRoute)); + Navigation.navigate(ROUTES.getCountryRoute(countryCode, activeRoute)); }} /> diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js index 6c9cbbb677db..02b1ba9066d6 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js @@ -25,6 +25,7 @@ const propTypes = { }).isRequired, /** Navigation from react-navigation */ navigation: PropTypes.shape({ + /** getState function retrieves the current navigation state from react-navigation's navigation property */ getState: PropTypes.func.isRequired, }).isRequired, }; @@ -53,11 +54,15 @@ function CountrySelection({route, navigation}) { (option) => { const backTo = lodashGet(route, 'params.backTo', ''); + // Check the navigation state and "backTo" parameter to decide navigation behavior if (navigation.getState().routes.length === 1 && _.isEmpty(backTo)) { + // If there is only one route and "backTo" is empty, go back in navigation Navigation.goBack(); } else if (!_.isEmpty(backTo) && navigation.getState().routes.length === 1) { + // If "backTo" is not empty and there is only one route, go back to the specific route defined in "backTo" with a country parameter Navigation.goBack(`${route.params.backTo}?country=${option.value}`); } else { + // Otherwise, navigate to the specific route defined in "backTo" with a country parameter Navigation.navigate(`${route.params.backTo}?country=${option.value}`); } }, From 55253e795f7c92edf08447500c56931a1dd6e7cf Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Thu, 7 Sep 2023 21:01:04 +0530 Subject: [PATCH 13/48] Rename CountrySelection to CountrySelectionPage --- .../PersonalDetails/CountrySelectionPage.js | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js new file mode 100644 index 000000000000..31b48619c575 --- /dev/null +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js @@ -0,0 +1,101 @@ +import React, {useState, useMemo, useCallback} from 'react'; +import PropTypes from 'prop-types'; +import _ from 'underscore'; +import lodashGet from 'lodash/get'; +import Navigation from '../../../../libs/Navigation/Navigation'; +import ScreenWrapper from '../../../../components/ScreenWrapper'; +import HeaderWithBackButton from '../../../../components/HeaderWithBackButton'; +import SelectionList from '../../../../components/SelectionList'; +import searchCountryOptions from '../../../../libs/searchCountryOptions'; +import StringUtils from '../../../../libs/StringUtils'; + +import useLocalize from '../../../../hooks/useLocalize'; + +const propTypes = { + /** Route from navigation */ + route: PropTypes.shape({ + /** Params from the route */ + params: PropTypes.shape({ + /** Currently selected country */ + country: PropTypes.string, + + /** Route to navigate back after selecting a currency */ + backTo: PropTypes.string, + }), + }).isRequired, + /** Navigation from react-navigation */ + navigation: PropTypes.shape({ + /** getState function retrieves the current navigation state from react-navigation's navigation property */ + getState: PropTypes.func.isRequired, + }).isRequired, +}; + +function CountrySelectionPage({route, navigation}) { + const [searchValue, setSearchValue] = useState(''); + const {translate} = useLocalize(); + const currentCountry = lodashGet(route, 'params.country'); + + const countries = useMemo( + () => + _.map(translate('allCountries'), (countryName, countryISO) => ({ + value: countryISO, + keyForList: countryISO, + text: countryName, + isSelected: currentCountry === countryISO, + searchValue: StringUtils.sanitizeString(`${countryISO}${countryName}`), + })), + [translate, currentCountry], + ); + + const searchResults = searchCountryOptions(searchValue, countries); + const headerMessage = searchValue.trim() && !searchResults.length ? translate('common.noResultsFound') : ''; + + const selectCountry = useCallback( + (option) => { + const backTo = lodashGet(route, 'params.backTo', ''); + + // Check the navigation state and "backTo" parameter to decide navigation behavior + if (navigation.getState().routes.length === 1 && _.isEmpty(backTo)) { + // If there is only one route and "backTo" is empty, go back in navigation + Navigation.goBack(); + } else if (!_.isEmpty(backTo) && navigation.getState().routes.length === 1) { + // If "backTo" is not empty and there is only one route, go back to the specific route defined in "backTo" with a country parameter + Navigation.goBack(`${route.params.backTo}?country=${option.value}`); + } else { + // Otherwise, navigate to the specific route defined in "backTo" with a country parameter + Navigation.navigate(`${route.params.backTo}?country=${option.value}`); + } + }, + [route, navigation], + ); + + return ( + + { + const backTo = lodashGet(route, 'params.backTo', ''); + const backToRoute = backTo ? `${backTo}?country=${currentCountry}` : ''; + Navigation.goBack(backToRoute); + }} + /> + + + + ); +} + +CountrySelectionPage.displayName = 'CountrySelectionPage'; +CountrySelectionPage.propTypes = propTypes; + +export default CountrySelectionPage; From 4252fba4f71998ff46020edac06adb5f1162fd2c Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Thu, 7 Sep 2023 21:03:27 +0530 Subject: [PATCH 14/48] Rename CountrySelection to CountrySelectionPage --- .../AppNavigator/ModalStackNavigators.js | 2 +- .../PersonalDetails/CountrySelection.js | 101 ------------------ 2 files changed, 1 insertion(+), 102 deletions(-) delete mode 100644 src/pages/settings/Profile/PersonalDetails/CountrySelection.js diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index fa4b5f9587f9..9e3a1dc53ee7 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -442,7 +442,7 @@ const SettingsModalStackNavigator = createModalStackNavigator([ }, { getComponent: () => { - const CountrySelectionPage = require('../../../pages/settings/Profile/PersonalDetails/CountrySelection').default; + const CountrySelectionPage = require('../../../pages/settings/Profile/PersonalDetails/CountrySelectionPage').default; return CountrySelectionPage; }, name: 'Settings_PersonalDetails_Address_Country', diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js b/src/pages/settings/Profile/PersonalDetails/CountrySelection.js deleted file mode 100644 index 02b1ba9066d6..000000000000 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelection.js +++ /dev/null @@ -1,101 +0,0 @@ -import React, {useState, useMemo, useCallback} from 'react'; -import PropTypes from 'prop-types'; -import _ from 'underscore'; -import lodashGet from 'lodash/get'; -import Navigation from '../../../../libs/Navigation/Navigation'; -import ScreenWrapper from '../../../../components/ScreenWrapper'; -import HeaderWithBackButton from '../../../../components/HeaderWithBackButton'; -import SelectionList from '../../../../components/SelectionList'; -import searchCountryOptions from '../../../../libs/searchCountryOptions'; -import StringUtils from '../../../../libs/StringUtils'; - -import useLocalize from '../../../../hooks/useLocalize'; - -const propTypes = { - /** Route from navigation */ - route: PropTypes.shape({ - /** Params from the route */ - params: PropTypes.shape({ - /** Currently selected country */ - country: PropTypes.string, - - /** Route to navigate back after selecting a currency */ - backTo: PropTypes.string, - }), - }).isRequired, - /** Navigation from react-navigation */ - navigation: PropTypes.shape({ - /** getState function retrieves the current navigation state from react-navigation's navigation property */ - getState: PropTypes.func.isRequired, - }).isRequired, -}; - -function CountrySelection({route, navigation}) { - const [searchValue, setSearchValue] = useState(''); - const {translate} = useLocalize(); - const currentCountry = lodashGet(route, 'params.country'); - - const countries = useMemo( - () => - _.map(translate('allCountries'), (countryName, countryISO) => ({ - value: countryISO, - keyForList: countryISO, - text: countryName, - isSelected: currentCountry === countryISO, - searchValue: StringUtils.sanitizeString(`${countryISO}${countryName}`), - })), - [translate, currentCountry], - ); - - const searchResults = searchCountryOptions(searchValue, countries); - const headerMessage = searchValue.trim() && !searchResults.length ? translate('common.noResultsFound') : ''; - - const selectCountry = useCallback( - (option) => { - const backTo = lodashGet(route, 'params.backTo', ''); - - // Check the navigation state and "backTo" parameter to decide navigation behavior - if (navigation.getState().routes.length === 1 && _.isEmpty(backTo)) { - // If there is only one route and "backTo" is empty, go back in navigation - Navigation.goBack(); - } else if (!_.isEmpty(backTo) && navigation.getState().routes.length === 1) { - // If "backTo" is not empty and there is only one route, go back to the specific route defined in "backTo" with a country parameter - Navigation.goBack(`${route.params.backTo}?country=${option.value}`); - } else { - // Otherwise, navigate to the specific route defined in "backTo" with a country parameter - Navigation.navigate(`${route.params.backTo}?country=${option.value}`); - } - }, - [route, navigation], - ); - - return ( - - { - const backTo = lodashGet(route, 'params.backTo', ''); - const backToRoute = backTo ? `${backTo}?country=${currentCountry}` : ''; - Navigation.goBack(backToRoute); - }} - /> - - - - ); -} - -CountrySelection.displayName = 'CountrySelection'; -CountrySelection.propTypes = propTypes; - -export default CountrySelection; From 178d1004272cde14a461f68810509900ff2ad4cb Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Thu, 7 Sep 2023 21:41:12 +0530 Subject: [PATCH 15/48] AddressPage: revalidate input forms when country name changes --- src/components/CountryPickerMenuItem.js | 17 +++++++++++++++-- .../Profile/PersonalDetails/AddressPage.js | 4 ++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/components/CountryPickerMenuItem.js b/src/components/CountryPickerMenuItem.js index 82b1ed0a449a..c2b9bf784959 100644 --- a/src/components/CountryPickerMenuItem.js +++ b/src/components/CountryPickerMenuItem.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useEffect} from 'react'; import PropTypes from 'prop-types'; import {View} from 'react-native'; import styles from '../styles/styles'; @@ -11,6 +11,12 @@ import FormHelpMessage from './FormHelpMessage'; const propTypes = { /** Error text from form, e.g when no country is selected */ errorText: PropTypes.string, + /** function from form to call when the country changes, important for revalidation */ + onInputChange: PropTypes.func.isRequired, + /** Prop which states when country value changed */ + didCountryChange: PropTypes.bool.isRequired, + /** Function for setting didCountryChange to false */ + setDidCountryChange: PropTypes.func.isRequired, /** Current selected country */ value: PropTypes.string, }; @@ -20,13 +26,20 @@ const defaultProps = { value: '', }; -function CountryPickerMenuItem({errorText, value: countryCode}, ref) { +function CountryPickerMenuItem({errorText, value: countryCode, onInputChange, didCountryChange, setDidCountryChange}, ref) { const {translate} = useLocalize(); const countries = translate('allCountries'); const country = countries[countryCode] || ''; const countryTitleDescStyle = country.length === 0 ? styles.textNormal : null; + useEffect(() => { + // This will cause the form to revalidate and remove any error related to country name + if (!didCountryChange) return; + onInputChange(countryCode); + setDidCountryChange(false); + }, [didCountryChange, onInputChange, setDidCountryChange, countryCode]); + return ( { if (!countryFromUrl) return; handleAddressChange(countryFromUrl, 'country'); + setDidCountryChange(true); }, [countryFromUrl, handleAddressChange]); if (lodashGet(privatePersonalDetails, 'isLoading', true)) { @@ -190,6 +192,8 @@ function AddressPage({privatePersonalDetails, route}) { From c7dfa90aead64973ff7dcf798676d0221338587d Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 19 Sep 2023 20:23:08 +0530 Subject: [PATCH 16/48] CountyPicker refactoring --- src/components/CountryPickerMenuItem.js | 13 +++++-------- .../settings/Profile/PersonalDetails/AddressPage.js | 4 ---- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/components/CountryPickerMenuItem.js b/src/components/CountryPickerMenuItem.js index d5725b4409f7..5567957990c3 100644 --- a/src/components/CountryPickerMenuItem.js +++ b/src/components/CountryPickerMenuItem.js @@ -13,12 +13,11 @@ const propTypes = { errorText: PropTypes.string, /** function from form to call when the country changes, important for revalidation */ onInputChange: PropTypes.func.isRequired, - /** Prop which states when country value changed */ - didCountryChange: PropTypes.bool.isRequired, - /** Function for setting didCountryChange to false */ - setDidCountryChange: PropTypes.func.isRequired, /** Current selected country */ value: PropTypes.string, + /** inputID used by the Form component */ + // eslint-disable-next-line react/no-unused-prop-types + inputID: PropTypes.string.isRequired, }; const defaultProps = { @@ -26,7 +25,7 @@ const defaultProps = { value: '', }; -function CountryPickerMenuItem({errorText, value: countryCode, onInputChange, didCountryChange, setDidCountryChange}, ref) { +function CountryPickerMenuItem({errorText, value: countryCode, onInputChange}, ref) { const {translate} = useLocalize(); const title = countryCode ? translate(`allCountries.${countryCode}`) : ''; @@ -34,10 +33,8 @@ function CountryPickerMenuItem({errorText, value: countryCode, onInputChange, di useEffect(() => { // This will cause the form to revalidate and remove any error related to country name - if (!didCountryChange) return; onInputChange(countryCode); - setDidCountryChange(false); - }, [didCountryChange, onInputChange, setDidCountryChange, countryCode]); + }, [countryCode]); return ( diff --git a/src/pages/settings/Profile/PersonalDetails/AddressPage.js b/src/pages/settings/Profile/PersonalDetails/AddressPage.js index adceb3b01cb4..9903902c233b 100644 --- a/src/pages/settings/Profile/PersonalDetails/AddressPage.js +++ b/src/pages/settings/Profile/PersonalDetails/AddressPage.js @@ -72,7 +72,6 @@ function AddressPage({privatePersonalDetails, route}) { const {translate} = useLocalize(); const countryFromUrl = lodashGet(route, 'params.country'); const [currentCountry, setCurrentCountry] = useState(countryFromUrl || PersonalDetails.getCountryISO(lodashGet(privatePersonalDetails, 'address.country'))); - const [didCountryChange, setDidCountryChange] = useState(false); const isUSAForm = currentCountry === CONST.COUNTRY.US; const zipSampleFormat = lodashGet(CONST.COUNTRY_ZIP_REGEX_DATA, [currentCountry, 'samples'], ''); const zipFormat = translate('common.zipCodeExampleFormat', {zipSampleFormat}); @@ -141,7 +140,6 @@ function AddressPage({privatePersonalDetails, route}) { useEffect(() => { if (!countryFromUrl) return; handleAddressChange(countryFromUrl, 'country'); - setDidCountryChange(true); }, [countryFromUrl, handleAddressChange]); return ( @@ -192,8 +190,6 @@ function AddressPage({privatePersonalDetails, route}) { From fc551b820e5c2ac27c47a5d6d93e2ee39058b5a1 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 19 Sep 2023 20:25:12 +0530 Subject: [PATCH 17/48] Rename CountryPickerMenuItem to CountrySelector --- .../{CountryPickerMenuItem.js => CountrySelector.js} | 10 +++++----- .../settings/Profile/PersonalDetails/AddressPage.js | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) rename src/components/{CountryPickerMenuItem.js => CountrySelector.js} (86%) diff --git a/src/components/CountryPickerMenuItem.js b/src/components/CountrySelector.js similarity index 86% rename from src/components/CountryPickerMenuItem.js rename to src/components/CountrySelector.js index 5567957990c3..4bee322bf99f 100644 --- a/src/components/CountryPickerMenuItem.js +++ b/src/components/CountrySelector.js @@ -25,7 +25,7 @@ const defaultProps = { value: '', }; -function CountryPickerMenuItem({errorText, value: countryCode, onInputChange}, ref) { +function CountrySelector({errorText, value: countryCode, onInputChange}, ref) { const {translate} = useLocalize(); const title = countryCode ? translate(`allCountries.${countryCode}`) : ''; @@ -56,8 +56,8 @@ function CountryPickerMenuItem({errorText, value: countryCode, onInputChange}, r ); } -CountryPickerMenuItem.propTypes = propTypes; -CountryPickerMenuItem.defaultProps = defaultProps; -CountryPickerMenuItem.displayName = 'CountryPickerMenuItem'; +CountrySelector.propTypes = propTypes; +CountrySelector.defaultProps = defaultProps; +CountrySelector.displayName = 'CountrySelector'; -export default React.forwardRef(CountryPickerMenuItem); +export default React.forwardRef(CountrySelector); diff --git a/src/pages/settings/Profile/PersonalDetails/AddressPage.js b/src/pages/settings/Profile/PersonalDetails/AddressPage.js index 9903902c233b..8cad30422f09 100644 --- a/src/pages/settings/Profile/PersonalDetails/AddressPage.js +++ b/src/pages/settings/Profile/PersonalDetails/AddressPage.js @@ -21,7 +21,7 @@ import ROUTES from '../../../../ROUTES'; import useLocalize from '../../../../hooks/useLocalize'; import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails'; import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator'; -import CountryPickerMenuItem from '../../../../components/CountryPickerMenuItem'; +import CountrySelector from '../../../../components/CountrySelector'; const propTypes = { /* Onyx Props */ @@ -189,7 +189,7 @@ function AddressPage({privatePersonalDetails, route}) { /> - From 137790cb4a7208afeba5481e1ffd68ade5ebd20f Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt <65986357+ygshbht@users.noreply.github.com> Date: Tue, 19 Sep 2023 20:35:13 +0530 Subject: [PATCH 18/48] Refactoring src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js Co-authored-by: Rajat Parashar --- .../settings/Profile/PersonalDetails/CountrySelectionPage.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js index d14d03dd87d3..e45060b35879 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js @@ -23,6 +23,7 @@ const propTypes = { backTo: PropTypes.string, }), }).isRequired, + /** Navigation from react-navigation */ navigation: PropTypes.shape({ /** getState function retrieves the current navigation state from react-navigation's navigation property */ From a49e1aac57821d2bf8230c22499b95c081e62887 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt <65986357+ygshbht@users.noreply.github.com> Date: Tue, 19 Sep 2023 20:35:40 +0530 Subject: [PATCH 19/48] Refactor src/pages/settings/Profile/PersonalDetails/AddressPage.js Co-authored-by: Rajat Parashar --- src/pages/settings/Profile/PersonalDetails/AddressPage.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/settings/Profile/PersonalDetails/AddressPage.js b/src/pages/settings/Profile/PersonalDetails/AddressPage.js index 8cad30422f09..949a0820228c 100644 --- a/src/pages/settings/Profile/PersonalDetails/AddressPage.js +++ b/src/pages/settings/Profile/PersonalDetails/AddressPage.js @@ -37,6 +37,7 @@ const propTypes = { country: PropTypes.string, }), }), + /** Route from navigation */ route: PropTypes.shape({ /** Params from the route */ From 19a1e7e866aaae6f606682bba6ff6862d6b91980 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt <65986357+ygshbht@users.noreply.github.com> Date: Tue, 19 Sep 2023 20:36:07 +0530 Subject: [PATCH 20/48] Refactor src/components/CountrySelector.js Co-authored-by: Rajat Parashar --- src/components/CountrySelector.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/CountrySelector.js b/src/components/CountrySelector.js index 4bee322bf99f..a16ff089363f 100644 --- a/src/components/CountrySelector.js +++ b/src/components/CountrySelector.js @@ -9,12 +9,15 @@ import MenuItemWithTopDescription from './MenuItemWithTopDescription'; import FormHelpMessage from './FormHelpMessage'; const propTypes = { - /** Error text from form, e.g when no country is selected */ + /** Form error text. e.g when no country is selected */ errorText: PropTypes.string, - /** function from form to call when the country changes, important for revalidation */ + + /** Callback called when the country changes. */ onInputChange: PropTypes.func.isRequired, + /** Current selected country */ value: PropTypes.string, + /** inputID used by the Form component */ // eslint-disable-next-line react/no-unused-prop-types inputID: PropTypes.string.isRequired, From 2cca5c0cb494c86e32c8385f8724d9cbbdaffed2 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 19 Sep 2023 20:38:36 +0530 Subject: [PATCH 21/48] Pull from remote --- src/components/CountrySelector.js | 6 +++--- .../Profile/PersonalDetails/CountrySelectionPage.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/CountrySelector.js b/src/components/CountrySelector.js index a16ff089363f..03c176570287 100644 --- a/src/components/CountrySelector.js +++ b/src/components/CountrySelector.js @@ -11,13 +11,13 @@ import FormHelpMessage from './FormHelpMessage'; const propTypes = { /** Form error text. e.g when no country is selected */ errorText: PropTypes.string, - + /** Callback called when the country changes. */ onInputChange: PropTypes.func.isRequired, - + /** Current selected country */ value: PropTypes.string, - + /** inputID used by the Form component */ // eslint-disable-next-line react/no-unused-prop-types inputID: PropTypes.string.isRequired, diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js index e45060b35879..79bc86f5498f 100644 --- a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js +++ b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js @@ -23,7 +23,7 @@ const propTypes = { backTo: PropTypes.string, }), }).isRequired, - + /** Navigation from react-navigation */ navigation: PropTypes.shape({ /** getState function retrieves the current navigation state from react-navigation's navigation property */ From 91045391c537b4e19c090fc282b421844890d68a Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 19 Sep 2023 20:39:08 +0530 Subject: [PATCH 22/48] Disable eslint warning CountrySelector --- src/components/CountrySelector.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/CountrySelector.js b/src/components/CountrySelector.js index 03c176570287..e508bc160f82 100644 --- a/src/components/CountrySelector.js +++ b/src/components/CountrySelector.js @@ -37,6 +37,7 @@ function CountrySelector({errorText, value: countryCode, onInputChange}, ref) { useEffect(() => { // This will cause the form to revalidate and remove any error related to country name onInputChange(countryCode); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [countryCode]); return ( From e81fe77b1f53612109da34523b336774d4321d20 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Wed, 20 Sep 2023 09:53:44 +0530 Subject: [PATCH 23/48] CountrySelector refactoring --- src/components/CountrySelector.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/CountrySelector.js b/src/components/CountrySelector.js index e508bc160f82..3a944bab5840 100644 --- a/src/components/CountrySelector.js +++ b/src/components/CountrySelector.js @@ -21,14 +21,18 @@ const propTypes = { /** inputID used by the Form component */ // eslint-disable-next-line react/no-unused-prop-types inputID: PropTypes.string.isRequired, + + /** React ref being forwarded to the MenuItemWithTopDescription */ + forwardedRef: PropTypes.func, }; const defaultProps = { errorText: '', value: '', + forwardedRef: () => {}, }; -function CountrySelector({errorText, value: countryCode, onInputChange}, ref) { +function CountrySelector({errorText, value: countryCode, onInputChange, forwardedRef}) { const {translate} = useLocalize(); const title = countryCode ? translate(`allCountries.${countryCode}`) : ''; @@ -45,7 +49,7 @@ function CountrySelector({errorText, value: countryCode, onInputChange}, ref) { { @@ -64,4 +68,10 @@ CountrySelector.propTypes = propTypes; CountrySelector.defaultProps = defaultProps; CountrySelector.displayName = 'CountrySelector'; -export default React.forwardRef(CountrySelector); +export default React.forwardRef((props, ref) => ( + +)); From 2ad5ec867046742d2a07d2c218d0e5751e110281 Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Wed, 20 Sep 2023 08:43:38 +0200 Subject: [PATCH 24/48] Update Task Report System Messages and LHN Display for Consistency --- src/components/TaskHeaderActionButton.js | 2 +- src/languages/en.ts | 2 +- src/languages/es.ts | 2 +- src/libs/ReportUtils.js | 10 +++++----- src/libs/actions/Task.js | 6 +++--- src/pages/home/HeaderView.js | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/TaskHeaderActionButton.js b/src/components/TaskHeaderActionButton.js index aa7694095f5b..bd903b8bcade 100644 --- a/src/components/TaskHeaderActionButton.js +++ b/src/components/TaskHeaderActionButton.js @@ -36,7 +36,7 @@ function TaskHeaderActionButton(props) { success isDisabled={ReportUtils.isCanceledTaskReport(props.report) || !Task.canModifyTask(props.report, props.session.accountID)} medium - text={props.translate(ReportUtils.isCompletedTaskReport(props.report) ? 'task.markAsIncomplete' : 'task.markAsDone')} + text={props.translate(ReportUtils.isCompletedTaskReport(props.report) ? 'task.markAsIncomplete' : 'task.markAsComplete')} onPress={() => ReportUtils.isCompletedTaskReport(props.report) ? Task.reopenTask(props.report, props.report.reportName) : Task.completeTask(props.report, props.report.reportName) } diff --git a/src/languages/en.ts b/src/languages/en.ts index b0f5801a30c3..2af7083a4b2e 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1518,7 +1518,7 @@ export default { reopened: 'reopened task', error: 'You do not have the permission to do the requested action.', }, - markAsDone: 'Mark as done', + markAsComplete: 'Mark as complete', markAsIncomplete: 'Mark as incomplete', assigneeError: 'There was an error assigning this task, please try another assignee.', }, diff --git a/src/languages/es.ts b/src/languages/es.ts index 1984624e8683..5c2297a36600 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1540,7 +1540,7 @@ export default { reopened: 'tarea reabrir', error: 'No tiene permiso para realizar la acción solicitada.', }, - markAsDone: 'Marcar como completada', + markAsComplete: 'Marcar como completada', markAsIncomplete: 'Marcar como incompleta', assigneeError: 'Hubo un error al asignar esta tarea, inténtalo con otro usuario.', }, diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 7c807112613c..3b648301189b 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2465,7 +2465,7 @@ function buildOptimisticCreatedReportAction(emailCreatingAction) { { type: CONST.REPORT.MESSAGE.TYPE.TEXT, style: 'strong', - text: emailCreatingAction === currentUserEmail ? 'You' : emailCreatingAction, + text: emailCreatingAction, }, { type: CONST.REPORT.MESSAGE.TYPE.TEXT, @@ -2504,7 +2504,7 @@ function buildOptimisticEditedTaskReportAction(emailEditingTask) { { type: CONST.REPORT.MESSAGE.TYPE.TEXT, style: 'strong', - text: emailEditingTask === currentUserEmail ? 'You' : emailEditingTask, + text: emailEditingTask, }, { type: CONST.REPORT.MESSAGE.TYPE.TEXT, @@ -2545,7 +2545,7 @@ function buildOptimisticClosedReportAction(emailClosingReport, policyName, reaso { type: CONST.REPORT.MESSAGE.TYPE.TEXT, style: 'strong', - text: emailClosingReport === currentUserEmail ? 'You' : emailClosingReport, + text: emailClosingReport, }, { type: CONST.REPORT.MESSAGE.TYPE.TEXT, @@ -3496,8 +3496,8 @@ function getTaskAssigneeChatOnyxData(accountID, assigneeEmail, assigneeAccountID // If you're choosing to share the task in the same DM as the assignee then we don't need to create another reportAction indicating that you've been assigned if (assigneeChatReportID !== parentReportID) { - optimisticAssigneeAddComment = buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `Assigned a task to you: ${title}`, parentReportID); - + const displayname = lodashGet(allPersonalDetails, [assigneeAccountID, 'displayName']) || lodashGet(personalDetails, [assigneeAccountID, 'login'], ''); + optimisticAssigneeAddComment = buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `assigned to: ${displayname}`, parentReportID); const lastAssigneeCommentText = formatReportLastMessageText(optimisticAssigneeAddComment.reportAction.message[0].text); const optimisticAssigneeReport = { lastVisibleActionCreated: currentTime, diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index f1fb4d96f523..b0014666839a 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -69,7 +69,7 @@ function createTaskAndNavigate(parentReportID, title, description, assigneeEmail // Parent ReportAction indicating that a task has been created const optimisticTaskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmail); - const optimisticAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `Created a task: ${title}`, parentReportID); + const optimisticAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `task for ${title}`, parentReportID); optimisticTaskReport.parentReportActionID = optimisticAddCommentReport.reportAction.reportActionID; const currentTime = DateUtils.getDBTime(); @@ -222,7 +222,7 @@ function createTaskAndNavigate(parentReportID, title, description, assigneeEmail */ function completeTask(taskReport, taskTitle) { const taskReportID = taskReport.reportID; - const message = `completed task: ${taskTitle}`; + const message = `marked as complete`; const completedTaskReportAction = ReportUtils.buildOptimisticTaskReportAction(taskReportID, CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED, message); const optimisticData = [ @@ -306,7 +306,7 @@ function completeTask(taskReport, taskTitle) { */ function reopenTask(taskReport, taskTitle) { const taskReportID = taskReport.reportID; - const message = `reopened task: ${taskTitle}`; + const message = `marked as incomplete`; const reopenedTaskReportAction = ReportUtils.buildOptimisticTaskReportAction(taskReportID, CONST.REPORT.ACTIONS.TYPE.TASKREOPENED, message); const optimisticData = [ diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 477d063c1747..6f9663852980 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -106,7 +106,7 @@ function HeaderView(props) { if (ReportUtils.isOpenTaskReport(props.report) && canModifyTask) { threeDotMenuItems.push({ icon: Expensicons.Checkmark, - text: props.translate('task.markAsDone'), + text: props.translate('task.markAsComplete'), onSelected: () => Task.completeTask(props.report, title), }); } From a9f58ef7febfa191402181002e697446f88ddc8b Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Thu, 21 Sep 2023 01:17:12 +0300 Subject: [PATCH 25/48] add condition for no onPreviewPressed prop --- src/components/ReportActionItem/MoneyRequestPreview.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 3a0741cf9bd2..6e6c615a5344 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -232,7 +232,12 @@ function MoneyRequestPreview(props) { errorRowStyles={[styles.mbn1]} needsOffscreenAlphaCompositing > - + {hasReceipt && ( Date: Thu, 21 Sep 2023 01:19:01 +0300 Subject: [PATCH 26/48] fix container corners not rounded while scanning --- src/styles/styles.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/styles/styles.js b/src/styles/styles.js index 7e8ad488d2ee..1d5807f783d9 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -3837,6 +3837,7 @@ const styles = (theme) => ({ reportPreviewBoxHoverBorder: { borderColor: theme.border, backgroundColor: theme.border, + borderRadius: variables.componentBorderRadiusLarge, }, reportPreviewBoxBody: { From c4b6378cec78e1ab614f2ae55f36ab0860a69834 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Thu, 21 Sep 2023 18:36:16 +0000 Subject: [PATCH 27/48] fix lint errors --- src/components/ReportActionItem/TaskPreview.js | 4 ++-- src/components/ReportActionItem/TaskView.js | 4 ++-- src/components/TaskHeaderActionButton.js | 4 +--- src/libs/ReportUtils.js | 2 +- src/libs/actions/Task.js | 6 ++---- src/pages/home/HeaderView.js | 4 ++-- 6 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/components/ReportActionItem/TaskPreview.js b/src/components/ReportActionItem/TaskPreview.js index d0181e3d736a..1f00f55251ca 100644 --- a/src/components/ReportActionItem/TaskPreview.js +++ b/src/components/ReportActionItem/TaskPreview.js @@ -94,9 +94,9 @@ function TaskPreview(props) { disabled={ReportUtils.isCanceledTaskReport(props.taskReport)} onPress={Session.checkIfActionIsAllowed(() => { if (isTaskCompleted) { - Task.reopenTask(props.taskReport, taskTitle); + Task.reopenTask(props.taskReport); } else { - Task.completeTask(props.taskReport, taskTitle); + Task.completeTask(props.taskReport); } })} accessibilityLabel={props.translate('task.task')} diff --git a/src/components/ReportActionItem/TaskView.js b/src/components/ReportActionItem/TaskView.js index f2a1758a050b..7bf408a9daa8 100644 --- a/src/components/ReportActionItem/TaskView.js +++ b/src/components/ReportActionItem/TaskView.js @@ -82,9 +82,9 @@ function TaskView(props) { { if (isCompleted) { - Task.reopenTask(props.report, taskTitle); + Task.reopenTask(props.report); } else { - Task.completeTask(props.report, taskTitle); + Task.completeTask(props.report); } })} isChecked={isCompleted} diff --git a/src/components/TaskHeaderActionButton.js b/src/components/TaskHeaderActionButton.js index bd903b8bcade..b22b5c92bf70 100644 --- a/src/components/TaskHeaderActionButton.js +++ b/src/components/TaskHeaderActionButton.js @@ -37,9 +37,7 @@ function TaskHeaderActionButton(props) { isDisabled={ReportUtils.isCanceledTaskReport(props.report) || !Task.canModifyTask(props.report, props.session.accountID)} medium text={props.translate(ReportUtils.isCompletedTaskReport(props.report) ? 'task.markAsIncomplete' : 'task.markAsComplete')} - onPress={() => - ReportUtils.isCompletedTaskReport(props.report) ? Task.reopenTask(props.report, props.report.reportName) : Task.completeTask(props.report, props.report.reportName) - } + onPress={() => (ReportUtils.isCompletedTaskReport(props.report) ? Task.reopenTask(props.report) : Task.completeTask(props.report))} style={[styles.flex1]} /> diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 3b648301189b..db1296f294cd 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -3496,7 +3496,7 @@ function getTaskAssigneeChatOnyxData(accountID, assigneeEmail, assigneeAccountID // If you're choosing to share the task in the same DM as the assignee then we don't need to create another reportAction indicating that you've been assigned if (assigneeChatReportID !== parentReportID) { - const displayname = lodashGet(allPersonalDetails, [assigneeAccountID, 'displayName']) || lodashGet(personalDetails, [assigneeAccountID, 'login'], ''); + const displayname = lodashGet(allPersonalDetails, [assigneeAccountID, 'displayName']) || lodashGet(allPersonalDetails, [assigneeAccountID, 'login'], ''); optimisticAssigneeAddComment = buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `assigned to: ${displayname}`, parentReportID); const lastAssigneeCommentText = formatReportLastMessageText(optimisticAssigneeAddComment.reportAction.message[0].text); const optimisticAssigneeReport = { diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index b0014666839a..12a21e047975 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -218,9 +218,8 @@ function createTaskAndNavigate(parentReportID, title, description, assigneeEmail /** * Complete a task * @param {Object} taskReport task report - * @param {String} taskTitle Title of the task */ -function completeTask(taskReport, taskTitle) { +function completeTask(taskReport) { const taskReportID = taskReport.reportID; const message = `marked as complete`; const completedTaskReportAction = ReportUtils.buildOptimisticTaskReportAction(taskReportID, CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED, message); @@ -302,9 +301,8 @@ function completeTask(taskReport, taskTitle) { /** * Reopen a closed task * @param {Object} taskReport task report - * @param {String} taskTitle Title of the task */ -function reopenTask(taskReport, taskTitle) { +function reopenTask(taskReport) { const taskReportID = taskReport.reportID; const message = `marked as incomplete`; const reopenedTaskReportAction = ReportUtils.buildOptimisticTaskReportAction(taskReportID, CONST.REPORT.ACTIONS.TYPE.TASKREOPENED, message); diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 6f9663852980..96149ce97a41 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -107,7 +107,7 @@ function HeaderView(props) { threeDotMenuItems.push({ icon: Expensicons.Checkmark, text: props.translate('task.markAsComplete'), - onSelected: () => Task.completeTask(props.report, title), + onSelected: () => Task.completeTask(props.report), }); } @@ -116,7 +116,7 @@ function HeaderView(props) { threeDotMenuItems.push({ icon: Expensicons.Checkmark, text: props.translate('task.markAsIncomplete'), - onSelected: () => Task.reopenTask(props.report, title), + onSelected: () => Task.reopenTask(props.report), }); } From c3ba15f9aaac3aaaed758210a8aa8c2c98915fd4 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:55:25 +0000 Subject: [PATCH 28/48] update task messages --- src/languages/en.ts | 4 ++-- src/languages/es.ts | 4 ++-- src/libs/SidebarUtils.js | 4 ++-- src/libs/actions/Task.js | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 2af7083a4b2e..a8c19b957721 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1513,9 +1513,9 @@ export default { assignee: 'Assignee', completed: 'Completed', messages: { - completed: 'completed task', + completed: 'marked as complete', canceled: 'deleted task', - reopened: 'reopened task', + reopened: 'marked as incomplete', error: 'You do not have the permission to do the requested action.', }, markAsComplete: 'Mark as complete', diff --git a/src/languages/es.ts b/src/languages/es.ts index 5c2297a36600..f74754bbe2fb 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1535,9 +1535,9 @@ export default { assignee: 'Usuario asignado', completed: 'Completada', messages: { - completed: 'tarea completada', + completed: 'marcada como completa', canceled: 'tarea eliminado', - reopened: 'tarea reabrir', + reopened: 'marcada como incompleta', error: 'No tiene permiso para realizar la acción solicitada.', }, markAsComplete: 'Marcar como completada', diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index f645697690e6..497bec400e1d 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -340,9 +340,9 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale, const newName = lodashGet(lastAction, 'originalMessage.newName', ''); result.alternateText = Localize.translate(preferredLocale, 'newRoomPage.roomRenamedTo', {newName}); } else if (lodashGet(lastAction, 'actionName', '') === CONST.REPORT.ACTIONS.TYPE.TASKREOPENED) { - result.alternateText = `${Localize.translate(preferredLocale, 'task.messages.reopened')}: ${report.reportName}`; + result.alternateText = `${Localize.translate(preferredLocale, 'task.messages.reopened')}`; } else if (lodashGet(lastAction, 'actionName', '') === CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED) { - result.alternateText = `${Localize.translate(preferredLocale, 'task.messages.completed')}: ${report.reportName}`; + result.alternateText = `${Localize.translate(preferredLocale, 'task.messages.completed')}`; } else { result.alternateText = lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet'); } diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index 12a21e047975..1976bea07965 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -938,7 +938,7 @@ function getTaskReportActionMessage(actionName, reportID, isCreateTaskAction) { taskStatusText = Localize.translateLocal('task.task'); } - return `${taskStatusText} ${report.reportName}`; + return `${taskStatusText}`; } export { From cc2e28203c7521d82710f695fed1bd16906f09d9 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:03:18 +0000 Subject: [PATCH 29/48] update task messages --- src/libs/actions/Task.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index 1976bea07965..e4b8274ee1fe 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -921,7 +921,7 @@ function clearEditTaskErrors(reportID) { function getTaskReportActionMessage(actionName, reportID, isCreateTaskAction) { const report = ReportUtils.getReport(reportID); if (isCreateTaskAction) { - return `Created a task: ${report.reportName}`; + return `task for ${title} ${report.reportName}`; } let taskStatusText = ''; switch (actionName) { From 30609b274448a2b88f8bef183b3d449e464a076e Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:09:03 +0000 Subject: [PATCH 30/48] update task messages --- src/libs/actions/Task.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index e4b8274ee1fe..e7a383a8894a 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -921,7 +921,7 @@ function clearEditTaskErrors(reportID) { function getTaskReportActionMessage(actionName, reportID, isCreateTaskAction) { const report = ReportUtils.getReport(reportID); if (isCreateTaskAction) { - return `task for ${title} ${report.reportName}`; + return `task for ${report.reportName}`; } let taskStatusText = ''; switch (actionName) { From c93a9612999ec2433a605359510535f307205e1d Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:18:10 +0000 Subject: [PATCH 31/48] update task messages --- src/libs/actions/Task.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index e7a383a8894a..77219c0b0930 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -69,7 +69,7 @@ function createTaskAndNavigate(parentReportID, title, description, assigneeEmail // Parent ReportAction indicating that a task has been created const optimisticTaskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmail); - const optimisticAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `task for ${title}`, parentReportID); + const optimisticAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `${currentUserAccountID}: task for ${title}`, parentReportID); optimisticTaskReport.parentReportActionID = optimisticAddCommentReport.reportAction.reportActionID; const currentTime = DateUtils.getDBTime(); From a8eeafd62e32c56837898d70a604b57208ca2dac Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:22:48 +0000 Subject: [PATCH 32/48] update task messages --- src/libs/actions/Task.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index 77219c0b0930..e03b06156533 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -69,7 +69,8 @@ function createTaskAndNavigate(parentReportID, title, description, assigneeEmail // Parent ReportAction indicating that a task has been created const optimisticTaskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmail); - const optimisticAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `${currentUserAccountID}: task for ${title}`, parentReportID); + const displayName = lodashGet(personalDetails, [currentUserAccountID, 'displayName']) || lodashGet(personalDetails, [currentUserAccountID, 'login']); + const optimisticAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `${displayName}: task for ${title}`, parentReportID); optimisticTaskReport.parentReportActionID = optimisticAddCommentReport.reportAction.reportActionID; const currentTime = DateUtils.getDBTime(); From 9358bb525240d58ac58bd1850e8189eaa58957f0 Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:26:29 +0000 Subject: [PATCH 33/48] update task messages --- src/libs/actions/Task.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index e03b06156533..2e825f5f41b4 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -69,7 +69,7 @@ function createTaskAndNavigate(parentReportID, title, description, assigneeEmail // Parent ReportAction indicating that a task has been created const optimisticTaskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmail); - const displayName = lodashGet(personalDetails, [currentUserAccountID, 'displayName']) || lodashGet(personalDetails, [currentUserAccountID, 'login']); + const displayName = lodashGet(allPersonalDetails, [currentUserAccountID, 'displayName']) || lodashGet(allPersonalDetails, [currentUserAccountID, 'login']); const optimisticAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `${displayName}: task for ${title}`, parentReportID); optimisticTaskReport.parentReportActionID = optimisticAddCommentReport.reportAction.reportActionID; From b63b77a2181aa94325b8535957fb5f4b508224bb Mon Sep 17 00:00:00 2001 From: Rayane Djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Fri, 22 Sep 2023 11:31:51 +0000 Subject: [PATCH 34/48] update task messages --- src/libs/actions/Task.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index 2e825f5f41b4..e7a383a8894a 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -69,8 +69,7 @@ function createTaskAndNavigate(parentReportID, title, description, assigneeEmail // Parent ReportAction indicating that a task has been created const optimisticTaskCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmail); - const displayName = lodashGet(allPersonalDetails, [currentUserAccountID, 'displayName']) || lodashGet(allPersonalDetails, [currentUserAccountID, 'login']); - const optimisticAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `${displayName}: task for ${title}`, parentReportID); + const optimisticAddCommentReport = ReportUtils.buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `task for ${title}`, parentReportID); optimisticTaskReport.parentReportActionID = optimisticAddCommentReport.reportAction.reportActionID; const currentTime = DateUtils.getDBTime(); From a96a73904c910626d6e4ee8dac5c7fda14d18371 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Sat, 23 Sep 2023 16:13:34 +0530 Subject: [PATCH 35/48] Format code --- src/pages/settings/Profile/PersonalDetails/AddressPage.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/PersonalDetails/AddressPage.js b/src/pages/settings/Profile/PersonalDetails/AddressPage.js index 8ebd900455a2..9ce06841f6a6 100644 --- a/src/pages/settings/Profile/PersonalDetails/AddressPage.js +++ b/src/pages/settings/Profile/PersonalDetails/AddressPage.js @@ -139,7 +139,9 @@ function AddressPage({privatePersonalDetails, route}) { }, []); useEffect(() => { - if (!countryFromUrl) return; + if (!countryFromUrl) { + return; + } handleAddressChange(countryFromUrl, 'country'); }, [countryFromUrl, handleAddressChange]); From 822199cd9b1f0af527059f7f6cb5bcc6dab574c2 Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Sun, 24 Sep 2023 13:56:02 +0300 Subject: [PATCH 36/48] apply border radius only on RequestPreview --- src/components/ReportActionItem/MoneyRequestPreview.js | 2 +- src/styles/styles.js | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 6e6c615a5344..b865a8c01d71 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -234,7 +234,7 @@ function MoneyRequestPreview(props) { > diff --git a/src/styles/styles.js b/src/styles/styles.js index 1d5807f783d9..124a8e79f0f6 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -3837,6 +3837,9 @@ const styles = (theme) => ({ reportPreviewBoxHoverBorder: { borderColor: theme.border, backgroundColor: theme.border, + }, + + reportContainerBorderRadius: { borderRadius: variables.componentBorderRadiusLarge, }, From 71c6450ae653a35f0b7411a116a4a08fd844dbdf Mon Sep 17 00:00:00 2001 From: Getabalew Tesfaye Date: Mon, 25 Sep 2023 12:54:36 +0300 Subject: [PATCH 37/48] simplify styling --- src/components/ReportActionItem/MoneyRequestPreview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js index 77510597d98d..35215cadd15d 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview.js +++ b/src/components/ReportActionItem/MoneyRequestPreview.js @@ -235,7 +235,7 @@ function MoneyRequestPreview(props) { > From 9d19973cb85e04a9e65bdcf81261ccae205d273d Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Mon, 25 Sep 2023 21:12:05 +0530 Subject: [PATCH 38/48] Formatting --- src/libs/Navigation/AppNavigator/ModalStackNavigators.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 612e65efe2b3..29cae97a219f 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -126,7 +126,7 @@ const SettingsModalStackNavigator = createModalStackNavigator({ Settings_PersonalDetails_LegalName: () => require('../../../pages/settings/Profile/PersonalDetails/LegalNamePage').default, Settings_PersonalDetails_DateOfBirth: () => require('../../../pages/settings/Profile/PersonalDetails/DateOfBirthPage').default, Settings_PersonalDetails_Address: () => require('../../../pages/settings/Profile/PersonalDetails/AddressPage').default, - Settings_PersonalDetails_Address_Country: () => require('../../../pages/settings/Profile/PersonalDetails/CountrySelectionPage').default , + Settings_PersonalDetails_Address_Country: () => require('../../../pages/settings/Profile/PersonalDetails/CountrySelectionPage').default, Settings_ContactMethods: () => require('../../../pages/settings/Profile/Contacts/ContactMethodsPage').default, Settings_ContactMethodDetails: () => require('../../../pages/settings/Profile/Contacts/ContactMethodDetailsPage').default, Settings_NewContactMethod: () => require('../../../pages/settings/Profile/Contacts/NewContactMethodPage').default, From 3af7931030512f6a458ca0fc2c73bb9cd29cd2f1 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Mon, 25 Sep 2023 21:21:13 +0530 Subject: [PATCH 39/48] Formatting --- src/libs/Navigation/AppNavigator/ModalStackNavigators.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 29cae97a219f..da3b2b5e618b 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -222,4 +222,4 @@ export { PrivateNotesModalStackNavigator, NewTeachersUniteNavigator, SignInModalStackNavigator, -}; \ No newline at end of file +}; From 945056d94d0db5960987adf964cea4b8e21c9b92 Mon Sep 17 00:00:00 2001 From: Yogesh Bhatt Date: Tue, 26 Sep 2023 14:38:49 +0530 Subject: [PATCH 40/48] set default prop value of 'value' of CountrySelector to undefined --- src/components/CountrySelector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CountrySelector.js b/src/components/CountrySelector.js index 74a8f3c126f9..2788f3cea8e3 100644 --- a/src/components/CountrySelector.js +++ b/src/components/CountrySelector.js @@ -28,7 +28,7 @@ const propTypes = { const defaultProps = { errorText: '', - value: '', + value: undefined, forwardedRef: () => {}, }; From b14d201b8922d56c994dc34a9cd9a0418fde1b60 Mon Sep 17 00:00:00 2001 From: David Cardoza Date: Wed, 27 Sep 2023 13:13:35 +0800 Subject: [PATCH 41/48] Update and rename Tax.md to Tax Tracking.md --- .../Tax Tracking.md | 19 +++++++++++++++++++ .../policy-and-domain-settings/Tax.md | 5 ----- 2 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 docs/articles/expensify-classic/policy-and-domain-settings/Tax Tracking.md delete mode 100644 docs/articles/expensify-classic/policy-and-domain-settings/Tax.md diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Tax Tracking.md b/docs/articles/expensify-classic/policy-and-domain-settings/Tax Tracking.md new file mode 100644 index 000000000000..106f5f9689b8 --- /dev/null +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Tax Tracking.md @@ -0,0 +1,19 @@ +--- +title: Tax +description: How to track expense taxes +--- +# Overview +Expensify’s tax tracking feature allows you to: +- Add tax names, rates, and codes whether you’re connected to an accounting system or not. +- Enable/disable taxes you’d like to make available to users. +- Set a default tax for policy currency expenses and, optionally, another default tax (including exempt) for foreign currency expenses which - will automatically apply to all new expenses. + +# How to Enable Tax Tracking +Tax tracking can be enabled in Tax section of the policy settings of any policy, whether group or individual. +## If Connected to an Accounting Integration +If your group policy is connected to Xero, QuickBooks Online, Sage Intacct, or NetSuite, make sure to first enable tax via the connection configuration page (Settings > Policies > Group > [Policy Name] > Connections > Configure) and then sync the connection. Your tax rates will be imported from the accounting system and indicated by its logo. +## Not Connected to an Accounting Integration +If your policy is not connected to an accounting system, go to Settings > Policies > Group > [Policy Name] > Tax to enable tax. + +# Tracking Tax by Expense Category +To set a different tax rate for a specific expense type in the policy currency, go Settings > Policies > Group > [Policy Name] > Categories page. Click "Edit Rules" next to the desired category and set the "Category default tax". This will be applied to new expenses, overriding the default policy currency tax rate. diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Tax.md b/docs/articles/expensify-classic/policy-and-domain-settings/Tax.md deleted file mode 100644 index 3ee1c8656b4b..000000000000 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Tax.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Coming Soon -description: Coming Soon ---- -## Resource Coming Soon! From ff307a7f2a912da5e720a4b7c893fdc8078adbdd Mon Sep 17 00:00:00 2001 From: David Cardoza Date: Wed, 27 Sep 2023 13:17:16 +0800 Subject: [PATCH 42/48] Update Tax Tracking.md Replace the term "policy" with "workspace" --- .../policy-and-domain-settings/Tax Tracking.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Tax Tracking.md b/docs/articles/expensify-classic/policy-and-domain-settings/Tax Tracking.md index 106f5f9689b8..d56869aed037 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Tax Tracking.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Tax Tracking.md @@ -6,14 +6,14 @@ description: How to track expense taxes Expensify’s tax tracking feature allows you to: - Add tax names, rates, and codes whether you’re connected to an accounting system or not. - Enable/disable taxes you’d like to make available to users. -- Set a default tax for policy currency expenses and, optionally, another default tax (including exempt) for foreign currency expenses which - will automatically apply to all new expenses. +- Set a default tax for Workspace currency expenses and, optionally, another default tax (including exempt) for foreign currency expenses which - will automatically apply to all new expenses. # How to Enable Tax Tracking -Tax tracking can be enabled in Tax section of the policy settings of any policy, whether group or individual. +Tax tracking can be enabled in Tax section of the Workspace settings of any Workspace, whether group or individual. ## If Connected to an Accounting Integration -If your group policy is connected to Xero, QuickBooks Online, Sage Intacct, or NetSuite, make sure to first enable tax via the connection configuration page (Settings > Policies > Group > [Policy Name] > Connections > Configure) and then sync the connection. Your tax rates will be imported from the accounting system and indicated by its logo. +If your group Workspace is connected to Xero, QuickBooks Online, Sage Intacct, or NetSuite, make sure to first enable tax via the connection configuration page (Settings > Policies > Group > [Workspace Name] > Connections > Configure) and then sync the connection. Your tax rates will be imported from the accounting system and indicated by its logo. ## Not Connected to an Accounting Integration -If your policy is not connected to an accounting system, go to Settings > Policies > Group > [Policy Name] > Tax to enable tax. +If your Workspace is not connected to an accounting system, go to Settings > Policies > Group > [Workspace Name] > Tax to enable tax. # Tracking Tax by Expense Category -To set a different tax rate for a specific expense type in the policy currency, go Settings > Policies > Group > [Policy Name] > Categories page. Click "Edit Rules" next to the desired category and set the "Category default tax". This will be applied to new expenses, overriding the default policy currency tax rate. +To set a different tax rate for a specific expense type in the Workspace currency, go Settings > Workspaces > Group > [Workspace Name] > Categories page. Click "Edit Rules" next to the desired category and set the "Category default tax". This will be applied to new expenses, overriding the default Workspace currency tax rate. From 51e51f06a68b97599a9b096860c2bd5972d485fe Mon Sep 17 00:00:00 2001 From: Rocio Perez-Cano Date: Wed, 27 Sep 2023 15:01:34 +0800 Subject: [PATCH 43/48] Rename Tax Tracking.md to tax-tracking.md --- .../{Tax Tracking.md => tax-tracking.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/articles/expensify-classic/policy-and-domain-settings/{Tax Tracking.md => tax-tracking.md} (100%) diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Tax Tracking.md b/docs/articles/expensify-classic/policy-and-domain-settings/tax-tracking.md similarity index 100% rename from docs/articles/expensify-classic/policy-and-domain-settings/Tax Tracking.md rename to docs/articles/expensify-classic/policy-and-domain-settings/tax-tracking.md From a30273c9db5043bdaa9515e74fcf5b75d27cc6ef Mon Sep 17 00:00:00 2001 From: David Cardoza Date: Wed, 27 Sep 2023 15:06:24 +0800 Subject: [PATCH 44/48] Update docs/articles/expensify-classic/policy-and-domain-settings/tax-tracking.md Co-authored-by: Rocio Perez-Cano --- .../policy-and-domain-settings/tax-tracking.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/tax-tracking.md b/docs/articles/expensify-classic/policy-and-domain-settings/tax-tracking.md index d56869aed037..fd6d44628c88 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/tax-tracking.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/tax-tracking.md @@ -9,7 +9,7 @@ Expensify’s tax tracking feature allows you to: - Set a default tax for Workspace currency expenses and, optionally, another default tax (including exempt) for foreign currency expenses which - will automatically apply to all new expenses. # How to Enable Tax Tracking -Tax tracking can be enabled in Tax section of the Workspace settings of any Workspace, whether group or individual. +Tax tracking can be enabled in the Tax section of the Workspace settings of any Workspace, whether group or individual. ## If Connected to an Accounting Integration If your group Workspace is connected to Xero, QuickBooks Online, Sage Intacct, or NetSuite, make sure to first enable tax via the connection configuration page (Settings > Policies > Group > [Workspace Name] > Connections > Configure) and then sync the connection. Your tax rates will be imported from the accounting system and indicated by its logo. ## Not Connected to an Accounting Integration From d28399cd922401ba2c1c29da9e71341fc0a7a2c4 Mon Sep 17 00:00:00 2001 From: David Cardoza Date: Wed, 27 Sep 2023 15:06:31 +0800 Subject: [PATCH 45/48] Update docs/articles/expensify-classic/policy-and-domain-settings/tax-tracking.md Co-authored-by: Rocio Perez-Cano --- .../policy-and-domain-settings/tax-tracking.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/tax-tracking.md b/docs/articles/expensify-classic/policy-and-domain-settings/tax-tracking.md index fd6d44628c88..7b859c5101b1 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/tax-tracking.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/tax-tracking.md @@ -16,4 +16,4 @@ If your group Workspace is connected to Xero, QuickBooks Online, Sage Intacct, o If your Workspace is not connected to an accounting system, go to Settings > Policies > Group > [Workspace Name] > Tax to enable tax. # Tracking Tax by Expense Category -To set a different tax rate for a specific expense type in the Workspace currency, go Settings > Workspaces > Group > [Workspace Name] > Categories page. Click "Edit Rules" next to the desired category and set the "Category default tax". This will be applied to new expenses, overriding the default Workspace currency tax rate. +To set a different tax rate for a specific expense type in the Workspace currency, go to Settings > Workspaces > Group > [Workspace Name] > Categories page. Click "Edit Rules" next to the desired category and set the "Category default tax". This will be applied to new expenses, overriding the default Workspace currency tax rate. From 3956c52fe7cbd37a4a4dc049f303515baf09c01a Mon Sep 17 00:00:00 2001 From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com> Date: Wed, 27 Sep 2023 11:04:37 +0100 Subject: [PATCH 46/48] Update assigned to message Co-authored-by: Eugene Voloshchak --- 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 16a34fcaf47d..8b77f1ad599b 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -3567,7 +3567,7 @@ function getTaskAssigneeChatOnyxData(accountID, assigneeEmail, assigneeAccountID // If you're choosing to share the task in the same DM as the assignee then we don't need to create another reportAction indicating that you've been assigned if (assigneeChatReportID !== parentReportID) { const displayname = lodashGet(allPersonalDetails, [assigneeAccountID, 'displayName']) || lodashGet(allPersonalDetails, [assigneeAccountID, 'login'], ''); - optimisticAssigneeAddComment = buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `assigned to: ${displayname}`, parentReportID); + optimisticAssigneeAddComment = buildOptimisticTaskCommentReportAction(taskReportID, title, assigneeEmail, assigneeAccountID, `assigned to ${displayname}`, parentReportID); const lastAssigneeCommentText = formatReportLastMessageText(optimisticAssigneeAddComment.reportAction.message[0].text); const optimisticAssigneeReport = { lastVisibleActionCreated: currentTime, From f2fc7fdfc22b5967dc95084c7cbc292116764291 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Wed, 27 Sep 2023 22:50:29 +0800 Subject: [PATCH 47/48] use lodashget to get the icons length --- src/components/OptionRow.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/OptionRow.js b/src/components/OptionRow.js index 8bc016faa6b5..70415ab03a13 100644 --- a/src/components/OptionRow.js +++ b/src/components/OptionRow.js @@ -212,7 +212,7 @@ class OptionRow extends Component { accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON} hoverDimmingValue={1} hoverStyle={this.props.hoverStyle} - needsOffscreenAlphaCompositing={this.props.option.icons.length >= 2} + needsOffscreenAlphaCompositing={lodashGet(this.props.option, 'icons.length', 0) >= 2} > From 529e9656d0583e97da3c72cd20f69c2ccda4df79 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Thu, 28 Sep 2023 15:05:10 +0800 Subject: [PATCH 48/48] Run prettier --- src/ROUTES.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index c3f8f6e58243..b2dafa643b22 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -92,7 +92,7 @@ export default { route += `&backTo=${encodeURIComponent(backTo)}`; } return route; - } + }, }, SETTINGS_CONTACT_METHODS: 'settings/profile/contact-methods', SETTINGS_CONTACT_METHOD_DETAILS: {