From 7890252dd642fe19f073747c5e5db5c921a73b45 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Wed, 23 Mar 2022 17:48:56 +0530 Subject: [PATCH 01/27] fix: localize currency symbol --- src/pages/iou/IOUCurrencySelection.js | 17 +++- src/pages/iou/steps/IOUAmountPage.js | 110 ++++++++++++++++++-------- 2 files changed, 93 insertions(+), 34 deletions(-) diff --git a/src/pages/iou/IOUCurrencySelection.js b/src/pages/iou/IOUCurrencySelection.js index 09ad555d5c0..b4005367a4a 100644 --- a/src/pages/iou/IOUCurrencySelection.js +++ b/src/pages/iou/IOUCurrencySelection.js @@ -81,6 +81,7 @@ class IOUCurrencySelection extends Component { this.getSections = this.getSections.bind(this); this.confirmCurrencySelection = this.confirmCurrencySelection.bind(this); this.changeSearchValue = this.changeSearchValue.bind(this); + this.getlocalizedCurrencySymbol = this.getlocalizedCurrencySymbol.bind(this); } componentDidMount() { @@ -113,13 +114,27 @@ class IOUCurrencySelection extends Component { getCurrencyOptions() { const currencyListKeys = _.keys(this.props.currencyList); const currencyOptions = _.map(currencyListKeys, currencyCode => ({ - text: `${currencyCode} - ${this.props.currencyList[currencyCode].symbol}`, + text: `${currencyCode} - ${this.getlocalizedCurrencySymbol(currencyCode)}`, searchText: `${currencyCode} ${this.props.currencyList[currencyCode].symbol}`, currencyCode, })); return currencyOptions; } + /** + * Get localized currency symbol for SO4217 Code + * @param {String} currencyCode + * @return {String} + */ + getlocalizedCurrencySymbol(currencyCode) { + const parts = new Intl.NumberFormat(this.props.preferredLocale, { + style: 'currency', + currency: currencyCode, + }).formatToParts(0); + const currencySymbol = _.find(parts, part => part.type === 'currency').value; + return currencySymbol; + } + /** * Function which toggles a currency in the list * diff --git a/src/pages/iou/steps/IOUAmountPage.js b/src/pages/iou/steps/IOUAmountPage.js index 5ebccbbcb6e..02870f54f91 100755 --- a/src/pages/iou/steps/IOUAmountPage.js +++ b/src/pages/iou/steps/IOUAmountPage.js @@ -31,18 +31,6 @@ const propTypes = { /** Callback to inform parent modal of success */ onStepComplete: PropTypes.func.isRequired, - /** The currency list constant object from Onyx */ - currencyList: PropTypes.objectOf(PropTypes.shape({ - /** Symbol for the currency */ - symbol: PropTypes.string, - - /** Name of the currency */ - name: PropTypes.string, - - /** ISO4217 Code for the currency */ - ISO4217: PropTypes.string, - })).isRequired, - /** Previously selected amount to show if the user comes back to this screen */ selectedAmount: PropTypes.string.isRequired, @@ -75,6 +63,8 @@ class IOUAmountPage extends React.Component { this.updateAmount = this.updateAmount.bind(this); this.stripCommaFromAmount = this.stripCommaFromAmount.bind(this); this.focusTextInput = this.focusTextInput.bind(this); + this.getlocalizedCurrencySymbol = this.getlocalizedCurrencySymbol.bind(this); + this.isCurrencySymbolToLeft = this.isCurrencySymbolToLeft.bind(this); this.state = { amount: props.selectedAmount, @@ -93,6 +83,37 @@ class IOUAmountPage extends React.Component { this.focusTextInput(); } + /** + * Get localized currency symbol for SO4217 Code + * @param {String} currencyCode + * @return {String} + */ + getlocalizedCurrencySymbol(currencyCode) { + const parts = new Intl.NumberFormat(this.props.preferredLocale, { + style: 'currency', + currency: currencyCode, + }).formatToParts(0); + const currencySymbol = _.find(parts, part => part.type === 'currency').value; + return currencySymbol; + } + + /** + * Is currency symbol to left + * @return {Boolean} + */ + isCurrencySymbolToLeft() { + const parts = new Intl.NumberFormat(this.props.preferredLocale, { + style: 'currency', + currency: this.props.iou.selectedCurrencyCode, + }).formatToParts(0); + + // The first element of parts will be type: currency for all currency + // Where it starts with symbol and the other will have it at last + // If it is not the first, it must be at last + const isLeft = parts[0].type === 'currency'; + return isLeft; + } + /** * Focus text input */ @@ -206,6 +227,7 @@ class IOUAmountPage extends React.Component { } render() { + const currencySymbol = this.getlocalizedCurrencySymbol(this.props.iou.selectedCurrencyCode); const formattedAmount = this.replaceAllDigits(this.state.amount, this.props.toLocaleDigit); return ( <> @@ -217,26 +239,49 @@ class IOUAmountPage extends React.Component { styles.justifyContentCenter, ]} > - Navigation.navigate(this.props.hasMultipleParticipants - ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) - : ROUTES.getIouRequestCurrencyRoute(this.props.reportID))} - > - - {lodashGet(this.props.currencyList, [this.props.iou.selectedCurrencyCode, 'symbol'])} - - - this.textInput = el} - value={formattedAmount} - placeholder={this.props.numberFormat(0)} - keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} - /> + {this.isCurrencySymbolToLeft() ? ( + <> + Navigation.navigate(this.props.hasMultipleParticipants + ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) + : ROUTES.getIouRequestCurrencyRoute(this.props.reportID))} + > + {currencySymbol} + + this.textInput = el} + value={formattedAmount} + placeholder={this.props.numberFormat(0)} + keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} + /> + + ) : ( + <> + this.textInput = el} + value={formattedAmount} + placeholder={this.props.numberFormat(0)} + keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} + /> + Navigation.navigate(this.props.hasMultipleParticipants + ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) + : ROUTES.getIouRequestCurrencyRoute(this.props.reportID))} + > + {currencySymbol} + + + )} {canUseTouchScreen() @@ -266,7 +311,6 @@ IOUAmountPage.defaultProps = defaultProps; export default compose( withLocalize, withOnyx({ - currencyList: {key: ONYXKEYS.CURRENCY_LIST}, iou: {key: ONYXKEYS.IOU}, }), )(IOUAmountPage); From 3fa9bc3fea5402670747186201cc0bfad2c37e69 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Mon, 28 Mar 2022 11:31:55 +0530 Subject: [PATCH 02/27] refactor: move common function to hoc component --- src/components/withLocalize.js | 31 +++++++++++++++++++++++++++ src/pages/iou/IOUCurrencySelection.js | 17 +-------------- src/pages/iou/steps/IOUAmountPage.js | 29 +++++++------------------ 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/components/withLocalize.js b/src/components/withLocalize.js index 1fb7c9ca9dc..5426cbcf1e5 100755 --- a/src/components/withLocalize.js +++ b/src/components/withLocalize.js @@ -1,6 +1,7 @@ import React, {createContext, forwardRef} from 'react'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; import getComponentDisplayName from '../libs/getComponentDisplayName'; import ONYXKEYS from '../ONYXKEYS'; import * as Localize from '../libs/Localize'; @@ -19,6 +20,9 @@ const withLocalizePropTypes = { /** Formats number formatted according to locale and options */ numberFormat: PropTypes.func.isRequired, + /** Formats number to parts according to locale and options */ + formatToParts: PropTypes.func.isRequired, + /** Converts a timestamp into a localized string representation that's relative to current moment in time */ timestampToRelative: PropTypes.func.isRequired, @@ -34,6 +38,9 @@ const withLocalizePropTypes = { /** Gets the standard digit corresponding to a locale digit */ fromLocaleDigit: PropTypes.func.isRequired, + /** Get localized currency symbol for SO4217 Code */ + toLocalizedCurrencySymbol: PropTypes.func.isRequired, + /** Gets the locale digit corresponding to a standard digit */ toLocaleDigit: PropTypes.func.isRequired, }; @@ -59,12 +66,14 @@ class LocaleContextProvider extends React.Component { return { translate: this.translate.bind(this), numberFormat: this.numberFormat.bind(this), + formatToParts: this.formatToParts.bind(this), timestampToRelative: this.timestampToRelative.bind(this), timestampToDateTime: this.timestampToDateTime.bind(this), fromLocalPhone: this.fromLocalPhone.bind(this), toLocalPhone: this.toLocalPhone.bind(this), fromLocaleDigit: this.fromLocaleDigit.bind(this), toLocaleDigit: this.toLocaleDigit.bind(this), + toLocalizedCurrencySymbol: this.toLocalizedCurrencySymbol.bind(this), preferredLocale: this.props.preferredLocale, }; } @@ -87,6 +96,15 @@ class LocaleContextProvider extends React.Component { return NumberFormatUtils.format(this.props.preferredLocale, number, options); } + /** + * @param {Number} number + * @param {Intl.NumberFormatOptions} options + * @returns {Array} + */ + formatToParts(number, options) { + return NumberFormatUtils.formatToParts(this.props.preferredLocale, number, options); + } + /** * @param {Number} timestamp * @returns {String} @@ -140,6 +158,19 @@ class LocaleContextProvider extends React.Component { return LocaleDigitUtils.fromLocaleDigit(this.props.preferredLocale, localeDigit); } + /** + * @param {String} currencyCode + * @return {String} + */ + toLocalizedCurrencySymbol(currencyCode) { + const parts = NumberFormatUtils.formatToParts(this.props.preferredLocale, 0, { + style: 'currency', + currency: currencyCode, + }); + const currencySymbol = _.find(parts, part => part.type === 'currency').value; + return currencySymbol; + } + render() { return ( diff --git a/src/pages/iou/IOUCurrencySelection.js b/src/pages/iou/IOUCurrencySelection.js index b4005367a4a..65161f36ea6 100644 --- a/src/pages/iou/IOUCurrencySelection.js +++ b/src/pages/iou/IOUCurrencySelection.js @@ -81,7 +81,6 @@ class IOUCurrencySelection extends Component { this.getSections = this.getSections.bind(this); this.confirmCurrencySelection = this.confirmCurrencySelection.bind(this); this.changeSearchValue = this.changeSearchValue.bind(this); - this.getlocalizedCurrencySymbol = this.getlocalizedCurrencySymbol.bind(this); } componentDidMount() { @@ -114,27 +113,13 @@ class IOUCurrencySelection extends Component { getCurrencyOptions() { const currencyListKeys = _.keys(this.props.currencyList); const currencyOptions = _.map(currencyListKeys, currencyCode => ({ - text: `${currencyCode} - ${this.getlocalizedCurrencySymbol(currencyCode)}`, + text: `${currencyCode} - ${this.props.toLocalizedCurrencySymbol(currencyCode)}`, searchText: `${currencyCode} ${this.props.currencyList[currencyCode].symbol}`, currencyCode, })); return currencyOptions; } - /** - * Get localized currency symbol for SO4217 Code - * @param {String} currencyCode - * @return {String} - */ - getlocalizedCurrencySymbol(currencyCode) { - const parts = new Intl.NumberFormat(this.props.preferredLocale, { - style: 'currency', - currency: currencyCode, - }).formatToParts(0); - const currencySymbol = _.find(parts, part => part.type === 'currency').value; - return currencySymbol; - } - /** * Function which toggles a currency in the list * diff --git a/src/pages/iou/steps/IOUAmountPage.js b/src/pages/iou/steps/IOUAmountPage.js index 02870f54f91..00fc6079d5c 100755 --- a/src/pages/iou/steps/IOUAmountPage.js +++ b/src/pages/iou/steps/IOUAmountPage.js @@ -63,7 +63,6 @@ class IOUAmountPage extends React.Component { this.updateAmount = this.updateAmount.bind(this); this.stripCommaFromAmount = this.stripCommaFromAmount.bind(this); this.focusTextInput = this.focusTextInput.bind(this); - this.getlocalizedCurrencySymbol = this.getlocalizedCurrencySymbol.bind(this); this.isCurrencySymbolToLeft = this.isCurrencySymbolToLeft.bind(this); this.state = { @@ -83,29 +82,16 @@ class IOUAmountPage extends React.Component { this.focusTextInput(); } - /** - * Get localized currency symbol for SO4217 Code - * @param {String} currencyCode - * @return {String} - */ - getlocalizedCurrencySymbol(currencyCode) { - const parts = new Intl.NumberFormat(this.props.preferredLocale, { - style: 'currency', - currency: currencyCode, - }).formatToParts(0); - const currencySymbol = _.find(parts, part => part.type === 'currency').value; - return currencySymbol; - } - /** * Is currency symbol to left + * @param {String} currencyCode * @return {Boolean} */ - isCurrencySymbolToLeft() { - const parts = new Intl.NumberFormat(this.props.preferredLocale, { + isCurrencySymbolToLeft(currencyCode) { + const parts = this.props.formatToParts(0, { style: 'currency', - currency: this.props.iou.selectedCurrencyCode, - }).formatToParts(0); + currency: currencyCode, + }); // The first element of parts will be type: currency for all currency // Where it starts with symbol and the other will have it at last @@ -227,8 +213,9 @@ class IOUAmountPage extends React.Component { } render() { - const currencySymbol = this.getlocalizedCurrencySymbol(this.props.iou.selectedCurrencyCode); + const currencySymbol = this.props.toLocalizedCurrencySymbol(this.props.iou.selectedCurrencyCode); const formattedAmount = this.replaceAllDigits(this.state.amount, this.props.toLocaleDigit); + const isCurrencySymbolToLeft = this.isCurrencySymbolToLeft(this.props.iou.selectedCurrencyCode); return ( <> - {this.isCurrencySymbolToLeft() ? ( + {isCurrencySymbolToLeft ? ( <> Navigation.navigate(this.props.hasMultipleParticipants ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) From fad813cca80d6138efd372999a90ebc1bbd73763 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Mon, 28 Mar 2022 15:43:48 +0530 Subject: [PATCH 03/27] refactor: rename variable names --- src/components/withLocalize.js | 30 +++++++++++++-------------- src/pages/iou/IOUCurrencySelection.js | 2 +- src/pages/iou/steps/IOUAmountPage.js | 10 ++++----- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/components/withLocalize.js b/src/components/withLocalize.js index 5426cbcf1e5..6d1175a2e4d 100755 --- a/src/components/withLocalize.js +++ b/src/components/withLocalize.js @@ -39,7 +39,7 @@ const withLocalizePropTypes = { fromLocaleDigit: PropTypes.func.isRequired, /** Get localized currency symbol for SO4217 Code */ - toLocalizedCurrencySymbol: PropTypes.func.isRequired, + getLocalizedCurrencySymbol: PropTypes.func.isRequired, /** Gets the locale digit corresponding to a standard digit */ toLocaleDigit: PropTypes.func.isRequired, @@ -73,11 +73,24 @@ class LocaleContextProvider extends React.Component { toLocalPhone: this.toLocalPhone.bind(this), fromLocaleDigit: this.fromLocaleDigit.bind(this), toLocaleDigit: this.toLocaleDigit.bind(this), - toLocalizedCurrencySymbol: this.toLocalizedCurrencySymbol.bind(this), + getLocalizedCurrencySymbol: this.getLocalizedCurrencySymbol.bind(this), preferredLocale: this.props.preferredLocale, }; } + /** + * @param {String} currencyCode + * @return {String} + */ + getLocalizedCurrencySymbol(currencyCode) { + const parts = NumberFormatUtils.formatToParts(this.props.preferredLocale, 0, { + style: 'currency', + currency: currencyCode, + }); + const currencySymbol = _.find(parts, part => part.type === 'currency').value; + return currencySymbol; + } + /** * @param {String} phrase * @param {Object} [variables] @@ -158,19 +171,6 @@ class LocaleContextProvider extends React.Component { return LocaleDigitUtils.fromLocaleDigit(this.props.preferredLocale, localeDigit); } - /** - * @param {String} currencyCode - * @return {String} - */ - toLocalizedCurrencySymbol(currencyCode) { - const parts = NumberFormatUtils.formatToParts(this.props.preferredLocale, 0, { - style: 'currency', - currency: currencyCode, - }); - const currencySymbol = _.find(parts, part => part.type === 'currency').value; - return currencySymbol; - } - render() { return ( diff --git a/src/pages/iou/IOUCurrencySelection.js b/src/pages/iou/IOUCurrencySelection.js index 65161f36ea6..fe103da3261 100644 --- a/src/pages/iou/IOUCurrencySelection.js +++ b/src/pages/iou/IOUCurrencySelection.js @@ -113,7 +113,7 @@ class IOUCurrencySelection extends Component { getCurrencyOptions() { const currencyListKeys = _.keys(this.props.currencyList); const currencyOptions = _.map(currencyListKeys, currencyCode => ({ - text: `${currencyCode} - ${this.props.toLocalizedCurrencySymbol(currencyCode)}`, + text: `${currencyCode} - ${this.props.getLocalizedCurrencySymbol(currencyCode)}`, searchText: `${currencyCode} ${this.props.currencyList[currencyCode].symbol}`, currencyCode, })); diff --git a/src/pages/iou/steps/IOUAmountPage.js b/src/pages/iou/steps/IOUAmountPage.js index 00fc6079d5c..1ae97c9718d 100755 --- a/src/pages/iou/steps/IOUAmountPage.js +++ b/src/pages/iou/steps/IOUAmountPage.js @@ -63,7 +63,7 @@ class IOUAmountPage extends React.Component { this.updateAmount = this.updateAmount.bind(this); this.stripCommaFromAmount = this.stripCommaFromAmount.bind(this); this.focusTextInput = this.focusTextInput.bind(this); - this.isCurrencySymbolToLeft = this.isCurrencySymbolToLeft.bind(this); + this.isCurrencySymbolLTR = this.isCurrencySymbolLTR.bind(this); this.state = { amount: props.selectedAmount, @@ -87,7 +87,7 @@ class IOUAmountPage extends React.Component { * @param {String} currencyCode * @return {Boolean} */ - isCurrencySymbolToLeft(currencyCode) { + isCurrencySymbolLTR(currencyCode) { const parts = this.props.formatToParts(0, { style: 'currency', currency: currencyCode, @@ -213,9 +213,9 @@ class IOUAmountPage extends React.Component { } render() { - const currencySymbol = this.props.toLocalizedCurrencySymbol(this.props.iou.selectedCurrencyCode); + const currencySymbol = this.props.getLocalizedCurrencySymbol(this.props.iou.selectedCurrencyCode); const formattedAmount = this.replaceAllDigits(this.state.amount, this.props.toLocaleDigit); - const isCurrencySymbolToLeft = this.isCurrencySymbolToLeft(this.props.iou.selectedCurrencyCode); + const isCurrencySymbolLTR = this.isCurrencySymbolLTR(this.props.iou.selectedCurrencyCode); return ( <> - {isCurrencySymbolToLeft ? ( + {isCurrencySymbolLTR ? ( <> Navigation.navigate(this.props.hasMultipleParticipants ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) From 0d56d96fab8d916f32ffd91403bee203a1092e27 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Mon, 28 Mar 2022 15:54:13 +0530 Subject: [PATCH 04/27] refactor: ltr symbol component --- src/pages/iou/steps/IOUAmountPage.js | 69 +++++++++++----------------- 1 file changed, 26 insertions(+), 43 deletions(-) diff --git a/src/pages/iou/steps/IOUAmountPage.js b/src/pages/iou/steps/IOUAmountPage.js index 1ae97c9718d..4aeec7931e3 100755 --- a/src/pages/iou/steps/IOUAmountPage.js +++ b/src/pages/iou/steps/IOUAmountPage.js @@ -216,6 +216,31 @@ class IOUAmountPage extends React.Component { const currencySymbol = this.props.getLocalizedCurrencySymbol(this.props.iou.selectedCurrencyCode); const formattedAmount = this.replaceAllDigits(this.state.amount, this.props.toLocaleDigit); const isCurrencySymbolLTR = this.isCurrencySymbolLTR(this.props.iou.selectedCurrencyCode); + + const currencySymbolElement = ( + Navigation.navigate(this.props.hasMultipleParticipants + ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) + : ROUTES.getIouRequestCurrencyRoute(this.props.reportID))} + > + {currencySymbol} + + ); + + const amountTextInput = ( + this.textInput = el} + value={formattedAmount} + placeholder={this.props.numberFormat(0)} + keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} + /> + ); + return ( <> - {isCurrencySymbolLTR ? ( - <> - Navigation.navigate(this.props.hasMultipleParticipants - ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) - : ROUTES.getIouRequestCurrencyRoute(this.props.reportID))} - > - {currencySymbol} - - this.textInput = el} - value={formattedAmount} - placeholder={this.props.numberFormat(0)} - keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} - /> - - ) : ( - <> - this.textInput = el} - value={formattedAmount} - placeholder={this.props.numberFormat(0)} - keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} - /> - Navigation.navigate(this.props.hasMultipleParticipants - ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) - : ROUTES.getIouRequestCurrencyRoute(this.props.reportID))} - > - {currencySymbol} - - - )} + {isCurrencySymbolLTR ? [currencySymbolElement, amountTextInput] : [amountTextInput, currencySymbolElement]} {canUseTouchScreen() From 1f5012287d6bcd579343f2e3847c58784d6dc29c Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Thu, 31 Mar 2022 11:12:17 +0530 Subject: [PATCH 05/27] feat: add currency symbol utils --- src/libs/CurrencySymbolUtils.js | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/libs/CurrencySymbolUtils.js diff --git a/src/libs/CurrencySymbolUtils.js b/src/libs/CurrencySymbolUtils.js new file mode 100644 index 00000000000..86d28dda2e1 --- /dev/null +++ b/src/libs/CurrencySymbolUtils.js @@ -0,0 +1,41 @@ +import _ from 'underscore'; +import * as NumberFormatUtils from './NumberFormatUtils'; + +/** + * Get localized currency symbol for SO4217 Code + * @param {String} preferredLocale + * @param {String} currencyCode + * @return {String} + */ +function getLocalizedCurrencySymbol(preferredLocale, currencyCode) { + const parts = NumberFormatUtils.formatToParts(preferredLocale, 0, { + style: 'currency', + currency: currencyCode, + }); + const currencySymbol = _.find(parts, part => part.type === 'currency').value; + return currencySymbol; +} + +/** + * Is currency symbol to left + * @param {String} preferredLocale + * @param {String} currencyCode + * @return {Boolean} + */ +function isCurrencySymbolLTR(preferredLocale, currencyCode) { + const parts = NumberFormatUtils.formatToParts(preferredLocale, 0, { + style: 'currency', + currency: currencyCode, + }); + + // The first element of parts will be type: currency for all currency + // Where it starts with symbol and the other will have it at last + // If it is not the first, it must be at last + const isLeft = parts[0].type === 'currency'; + return isLeft; +} + +export { + getLocalizedCurrencySymbol, + isCurrencySymbolLTR, +}; From df003d6955719390c603fa9a7de732c1debd726f Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Thu, 31 Mar 2022 11:16:36 +0530 Subject: [PATCH 06/27] refactor: currency utils functions --- src/components/withLocalize.js | 31 --------------------------- src/pages/iou/IOUCurrencySelection.js | 3 ++- src/pages/iou/steps/IOUAmountPage.js | 24 +++------------------ 3 files changed, 5 insertions(+), 53 deletions(-) diff --git a/src/components/withLocalize.js b/src/components/withLocalize.js index 6d1175a2e4d..1fb7c9ca9dc 100755 --- a/src/components/withLocalize.js +++ b/src/components/withLocalize.js @@ -1,7 +1,6 @@ import React, {createContext, forwardRef} from 'react'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import getComponentDisplayName from '../libs/getComponentDisplayName'; import ONYXKEYS from '../ONYXKEYS'; import * as Localize from '../libs/Localize'; @@ -20,9 +19,6 @@ const withLocalizePropTypes = { /** Formats number formatted according to locale and options */ numberFormat: PropTypes.func.isRequired, - /** Formats number to parts according to locale and options */ - formatToParts: PropTypes.func.isRequired, - /** Converts a timestamp into a localized string representation that's relative to current moment in time */ timestampToRelative: PropTypes.func.isRequired, @@ -38,9 +34,6 @@ const withLocalizePropTypes = { /** Gets the standard digit corresponding to a locale digit */ fromLocaleDigit: PropTypes.func.isRequired, - /** Get localized currency symbol for SO4217 Code */ - getLocalizedCurrencySymbol: PropTypes.func.isRequired, - /** Gets the locale digit corresponding to a standard digit */ toLocaleDigit: PropTypes.func.isRequired, }; @@ -66,31 +59,16 @@ class LocaleContextProvider extends React.Component { return { translate: this.translate.bind(this), numberFormat: this.numberFormat.bind(this), - formatToParts: this.formatToParts.bind(this), timestampToRelative: this.timestampToRelative.bind(this), timestampToDateTime: this.timestampToDateTime.bind(this), fromLocalPhone: this.fromLocalPhone.bind(this), toLocalPhone: this.toLocalPhone.bind(this), fromLocaleDigit: this.fromLocaleDigit.bind(this), toLocaleDigit: this.toLocaleDigit.bind(this), - getLocalizedCurrencySymbol: this.getLocalizedCurrencySymbol.bind(this), preferredLocale: this.props.preferredLocale, }; } - /** - * @param {String} currencyCode - * @return {String} - */ - getLocalizedCurrencySymbol(currencyCode) { - const parts = NumberFormatUtils.formatToParts(this.props.preferredLocale, 0, { - style: 'currency', - currency: currencyCode, - }); - const currencySymbol = _.find(parts, part => part.type === 'currency').value; - return currencySymbol; - } - /** * @param {String} phrase * @param {Object} [variables] @@ -109,15 +87,6 @@ class LocaleContextProvider extends React.Component { return NumberFormatUtils.format(this.props.preferredLocale, number, options); } - /** - * @param {Number} number - * @param {Intl.NumberFormatOptions} options - * @returns {Array} - */ - formatToParts(number, options) { - return NumberFormatUtils.formatToParts(this.props.preferredLocale, number, options); - } - /** * @param {Number} timestamp * @returns {String} diff --git a/src/pages/iou/IOUCurrencySelection.js b/src/pages/iou/IOUCurrencySelection.js index fe103da3261..4b3d488c5c0 100644 --- a/src/pages/iou/IOUCurrencySelection.js +++ b/src/pages/iou/IOUCurrencySelection.js @@ -20,6 +20,7 @@ import KeyboardAvoidingView from '../../components/KeyboardAvoidingView'; import Button from '../../components/Button'; import FixedFooter from '../../components/FixedFooter'; import * as IOU from '../../libs/actions/IOU'; +import * as CurrencySymbolUtils from '../../libs/CurrencySymbolUtils'; /** * IOU Currency selection for selecting currency @@ -113,7 +114,7 @@ class IOUCurrencySelection extends Component { getCurrencyOptions() { const currencyListKeys = _.keys(this.props.currencyList); const currencyOptions = _.map(currencyListKeys, currencyCode => ({ - text: `${currencyCode} - ${this.props.getLocalizedCurrencySymbol(currencyCode)}`, + text: `${currencyCode} - ${CurrencySymbolUtils.getLocalizedCurrencySymbol(this.props.preferredLocale, currencyCode)}`, searchText: `${currencyCode} ${this.props.currencyList[currencyCode].symbol}`, currencyCode, })); diff --git a/src/pages/iou/steps/IOUAmountPage.js b/src/pages/iou/steps/IOUAmountPage.js index 4aeec7931e3..40507812b0f 100755 --- a/src/pages/iou/steps/IOUAmountPage.js +++ b/src/pages/iou/steps/IOUAmountPage.js @@ -20,6 +20,7 @@ import Text from '../../../components/Text'; import CONST from '../../../CONST'; import TextInput from '../../../components/TextInput'; import canUseTouchScreen from '../../../libs/canUseTouchscreen'; +import * as CurrencySymbolUtils from '../../../libs/CurrencySymbolUtils'; const propTypes = { /** Whether or not this IOU has multiple participants */ @@ -63,7 +64,6 @@ class IOUAmountPage extends React.Component { this.updateAmount = this.updateAmount.bind(this); this.stripCommaFromAmount = this.stripCommaFromAmount.bind(this); this.focusTextInput = this.focusTextInput.bind(this); - this.isCurrencySymbolLTR = this.isCurrencySymbolLTR.bind(this); this.state = { amount: props.selectedAmount, @@ -82,24 +82,6 @@ class IOUAmountPage extends React.Component { this.focusTextInput(); } - /** - * Is currency symbol to left - * @param {String} currencyCode - * @return {Boolean} - */ - isCurrencySymbolLTR(currencyCode) { - const parts = this.props.formatToParts(0, { - style: 'currency', - currency: currencyCode, - }); - - // The first element of parts will be type: currency for all currency - // Where it starts with symbol and the other will have it at last - // If it is not the first, it must be at last - const isLeft = parts[0].type === 'currency'; - return isLeft; - } - /** * Focus text input */ @@ -213,9 +195,9 @@ class IOUAmountPage extends React.Component { } render() { - const currencySymbol = this.props.getLocalizedCurrencySymbol(this.props.iou.selectedCurrencyCode); const formattedAmount = this.replaceAllDigits(this.state.amount, this.props.toLocaleDigit); - const isCurrencySymbolLTR = this.isCurrencySymbolLTR(this.props.iou.selectedCurrencyCode); + const currencySymbol = CurrencySymbolUtils.getLocalizedCurrencySymbol(this.props.preferredLocale, this.props.iou.selectedCurrencyCode); + const isCurrencySymbolLTR = CurrencySymbolUtils.isCurrencySymbolLTR(this.props.preferredLocale, this.props.iou.selectedCurrencyCode); const currencySymbolElement = ( Navigation.navigate(this.props.hasMultipleParticipants From 3cd30fac61944ffa5661b77906356af665682853 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Fri, 1 Apr 2022 14:11:35 +0530 Subject: [PATCH 07/27] test: add CurrencySymbolUtilsTest --- tests/unit/CurrencySymbolUtilsTest.js | 36 ++ tests/unit/currencyList.json | 855 ++++++++++++++++++++++++++ 2 files changed, 891 insertions(+) create mode 100644 tests/unit/CurrencySymbolUtilsTest.js create mode 100644 tests/unit/currencyList.json diff --git a/tests/unit/CurrencySymbolUtilsTest.js b/tests/unit/CurrencySymbolUtilsTest.js new file mode 100644 index 00000000000..ff3ec6772d3 --- /dev/null +++ b/tests/unit/CurrencySymbolUtilsTest.js @@ -0,0 +1,36 @@ +const _ = require('underscore'); +import * as CurrencySymbolUtils from '../../src/libs/CurrencySymbolUtils'; +import currencyList from './currencyList.json'; + +const currencyCodeList = _.keys(currencyList); + +const AVAILABLE_LOCALES = ['en', 'es']; + +// Contains item [isLeft, locale, currencyCode] +const symbolPositions = [ + [true, 'en', 'USD'], + [false, 'es', 'USD'] +]; + + +describe('CurrencySymbolUtils', () => { + describe('getLocalizedCurrencySymbol', () => { + + test.each(AVAILABLE_LOCALES)('returns non empty string for all currencyCode with preferredLocale %s', (prefrredLocale) => { + _.forEach(currencyCodeList, (currencyCode) => { + const localizedSymbol = CurrencySymbolUtils.getLocalizedCurrencySymbol(prefrredLocale, currencyCode); + + expect(typeof localizedSymbol).toBe('string'); + expect(localizedSymbol.length).toBeGreaterThan(0); + }); + }); + }); + + describe('isCurrencySymbolLTR', () => { + + test.each(symbolPositions)('returns %s for prefrredLocale %s and currencyCode %s', (isLeft, locale, currencyCode) => { + const isSymbolLeft = CurrencySymbolUtils.isCurrencySymbolLTR(locale, currencyCode); + expect(isSymbolLeft).toBe(isLeft); + }); + }); +}); diff --git a/tests/unit/currencyList.json b/tests/unit/currencyList.json new file mode 100644 index 00000000000..740b3caf2b2 --- /dev/null +++ b/tests/unit/currencyList.json @@ -0,0 +1,855 @@ +{ + "AED": { + "symbol": "Dhs", + "name": "UAE Dirham", + "ISO4217": "784" + }, + "AFN": { + "symbol": "Af", + "name": "Afghan Afghani", + "ISO4217": "971" + }, + "ALL": { + "symbol": "ALL", + "name": "Albanian Lek", + "ISO4217": "008" + }, + "AMD": { + "symbol": "դր", + "name": "Armenian Dram", + "ISO4217": "051" + }, + "ANG": { + "symbol": "NAƒ", + "name": "Neth Antilles Guilder", + "ISO4217": "532" + }, + "AOA": { + "symbol": "Kz", + "name": "Angolan Kwanza", + "ISO4217": "973" + }, + "ARS": { + "symbol": "AR$", + "name": "Argentine Peso", + "ISO4217": "032" + }, + "AUD": { + "symbol": "A$", + "name": "Australian Dollar", + "ISO4217": "036" + }, + "AWG": { + "symbol": "ƒ", + "name": "Aruba Florin", + "ISO4217": "533" + }, + "AZN": { + "symbol": "man", + "name": "Azerbaijani Manat", + "ISO4217": "944" + }, + "BAM": { + "symbol": "KM", + "name": "Bosnia And Herzegovina Convertible Mark", + "ISO4217": "977" + }, + "BBD": { + "symbol": "Bds$", + "name": "Barbados Dollar", + "ISO4217": "052" + }, + "BDT": { + "symbol": "Tk", + "name": "Bangladesh Taka", + "ISO4217": "050" + }, + "BGN": { + "symbol": "лв", + "name": "Bulgarian Lev", + "ISO4217": "975" + }, + "BHD": { + "symbol": "BHD", + "name": "Bahraini Dinar", + "ISO4217": "048" + }, + "BIF": { + "symbol": "FBu", + "name": "Burundi Franc", + "decimals": 0, + "ISO4217": "108" + }, + "BMD": { + "symbol": "BD$", + "name": "Bermuda Dollar", + "ISO4217": "060" + }, + "BND": { + "symbol": "BN$", + "name": "Brunei Dollar", + "ISO4217": "096" + }, + "BOB": { + "symbol": "Bs", + "name": "Bolivian Boliviano", + "ISO4217": "068" + }, + "BRL": { + "symbol": "R$", + "name": "Brazilian Real", + "ISO4217": "986" + }, + "BSD": { + "symbol": "BS$", + "name": "Bahamian Dollar", + "ISO4217": "044" + }, + "BTN": { + "symbol": "Nu.", + "name": "Bhutan Ngultrum", + "ISO4217": "064" + }, + "BWP": { + "symbol": "P", + "name": "Botswana Pula", + "ISO4217": "072" + }, + "BYN": { + "symbol": "BR", + "name": "Belarus Ruble", + "ISO4217": "933" + }, + "BYR": { + "symbol": "BR", + "name": "Belarus Ruble", + "retired": true, + "retirementDate": "2016-07-01", + "ISO4217": "974" + }, + "BZD": { + "symbol": "BZ$", + "name": "Belize Dollar", + "ISO4217": "084" + }, + "CAD": { + "symbol": "C$", + "name": "Canadian Dollar", + "ISO4217": "124" + }, + "CDF": { + "symbol": "CDF", + "name": "Congolese Franc", + "ISO4217": "976" + }, + "CHF": { + "symbol": "CHF", + "name": "Swiss Franc", + "ISO4217": "756" + }, + "CLP": { + "symbol": "Ch$", + "name": "Chilean Peso", + "decimals": 0, + "ISO4217": "152" + }, + "CNY": { + "symbol": "¥", + "name": "Chinese Yuan", + "ISO4217": "156" + }, + "COP": { + "symbol": "Col$", + "name": "Colombian Peso", + "decimals": 0, + "ISO4217": "170" + }, + "CRC": { + "symbol": "CR₡", + "name": "Costa Rica Colon", + "ISO4217": "188" + }, + "CUC": { + "symbol": "CUC", + "name": "Cuban Convertible Peso", + "ISO4217": "931" + }, + "CUP": { + "symbol": "$MN", + "name": "Cuban Peso", + "ISO4217": "192" + }, + "CVE": { + "symbol": "Esc", + "name": "Cape Verde Escudo", + "ISO4217": "132" + }, + "CZK": { + "symbol": "Kč", + "name": "Czech Koruna", + "ISO4217": "203" + }, + "DJF": { + "symbol": "Fdj", + "name": "Dijibouti Franc", + "decimals": 0, + "ISO4217": "262" + }, + "DKK": { + "symbol": "Dkr", + "name": "Danish Krone", + "ISO4217": "208" + }, + "DOP": { + "symbol": "RD$", + "name": "Dominican Peso", + "ISO4217": "214" + }, + "DZD": { + "symbol": "DZD", + "name": "Algerian Dinar", + "ISO4217": "012" + }, + "EEK": { + "symbol": "KR", + "name": "Estonian Kroon", + "ISO4217": "", + "retired": true + }, + "EGP": { + "symbol": "EGP", + "name": "Egyptian Pound", + "ISO4217": "818" + }, + "ERN": { + "symbol": "Nfk", + "name": "Eritrea Nakfa", + "ISO4217": "232" + }, + "ETB": { + "symbol": "Br", + "name": "Ethiopian Birr", + "ISO4217": "230" + }, + "EUR": { + "symbol": "€", + "name": "Euro", + "ISO4217": "978" + }, + "FJD": { + "symbol": "FJ$", + "name": "Fiji Dollar", + "ISO4217": "242" + }, + "FKP": { + "symbol": "FK£", + "name": "Falkland Islands Pound", + "ISO4217": "238" + }, + "GBP": { + "symbol": "£", + "name": "British Pound", + "ISO4217": "826" + }, + "GEL": { + "symbol": "ლ", + "name": "Georgian Lari", + "ISO4217": "981" + }, + "GHS": { + "symbol": "₵", + "name": "Ghanaian Cedi", + "ISO4217": "936" + }, + "GIP": { + "symbol": "£G", + "name": "Gibraltar Pound", + "ISO4217": "292" + }, + "GMD": { + "symbol": "D", + "name": "Gambian Dalasi", + "ISO4217": "270" + }, + "GNF": { + "symbol": "FG", + "name": "Guinea Franc", + "decimals": 0, + "ISO4217": "324" + }, + "GTQ": { + "symbol": "Q", + "name": "Guatemala Quetzal", + "ISO4217": "320" + }, + "GYD": { + "symbol": "GY$", + "name": "Guyana Dollar", + "ISO4217": "328" + }, + "HKD": { + "symbol": "HK$", + "name": "Hong Kong Dollar", + "ISO4217": "344" + }, + "HNL": { + "symbol": "HNL", + "name": "Honduras Lempira", + "ISO4217": "340" + }, + "HRK": { + "symbol": "kn", + "name": "Croatian Kuna", + "ISO4217": "191" + }, + "HTG": { + "symbol": "G", + "name": "Haiti Gourde", + "ISO4217": "332" + }, + "HUF": { + "symbol": "Ft", + "name": "Hungarian Forint", + "ISO4217": "348" + }, + "IDR": { + "symbol": "Rp", + "name": "Indonesian Rupiah", + "ISO4217": "360" + }, + "ILS": { + "symbol": "₪", + "name": "Israeli Shekel", + "ISO4217": "376" + }, + "INR": { + "symbol": "₹", + "name": "Indian Rupee", + "ISO4217": "356" + }, + "IQD": { + "symbol": "IQD", + "name": "Iraqi Dinar", + "ISO4217": "368" + }, + "IRR": { + "symbol": "﷼", + "name": "Iran Rial", + "ISO4217": "364" + }, + "ISK": { + "symbol": "kr", + "name": "Iceland Krona", + "decimals": 0, + "ISO4217": "352" + }, + "JMD": { + "symbol": "J$", + "name": "Jamaican Dollar", + "ISO4217": "388" + }, + "JOD": { + "symbol": "JOD", + "name": "Jordanian Dinar", + "ISO4217": "400" + }, + "JPY": { + "symbol": "¥", + "name": "Japanese Yen", + "decimals": 0, + "ISO4217": "392" + }, + "KES": { + "symbol": "KSh", + "name": "Kenyan Shilling", + "ISO4217": "404" + }, + "KGS": { + "symbol": "KGS", + "name": "Kyrgyzstani Som", + "ISO4217": "417" + }, + "KHR": { + "symbol": "KHR", + "name": "Cambodia Riel", + "ISO4217": "116" + }, + "KMF": { + "symbol": "CF", + "name": "Comoros Franc", + "ISO4217": "174" + }, + "KPW": { + "symbol": "KP₩", + "name": "North Korean Won", + "ISO4217": "408" + }, + "KRW": { + "symbol": "₩", + "name": "Korean Won", + "ISO4217": "410" + }, + "KWD": { + "symbol": "KWD", + "name": "Kuwaiti Dinar", + "ISO4217": "414" + }, + "KYD": { + "symbol": "CI$", + "name": "Cayman Islands Dollar", + "ISO4217": "136" + }, + "KZT": { + "symbol": "〒", + "name": "Kazakhstan Tenge", + "ISO4217": "398" + }, + "LAK": { + "symbol": "₭", + "name": "Lao Kip", + "ISO4217": "418" + }, + "LBP": { + "symbol": "LBP", + "name": "Lebanese Pound", + "ISO4217": "422" + }, + "LKR": { + "symbol": "SL₨", + "name": "Sri Lanka Rupee", + "ISO4217": "144" + }, + "LRD": { + "symbol": "L$", + "name": "Liberian Dollar", + "ISO4217": "430" + }, + "LSL": { + "symbol": "M", + "name": "Lesotho Loti", + "ISO4217": "426" + }, + "LTL": { + "symbol": "Lt", + "name": "Lithuanian Lita", + "retirementDate": "2015-08-22", + "retired": true, + "ISO4217": "440" + }, + "LVL": { + "symbol": "Ls", + "name": "Latvian Lat", + "ISO4217": "428", + "retired": true + }, + "LYD": { + "symbol": "LYD", + "name": "Libyan Dinar", + "ISO4217": "434" + }, + "MAD": { + "symbol": "MAD", + "name": "Moroccan Dirham", + "ISO4217": "504" + }, + "MDL": { + "symbol": "MDL", + "name": "Moldovan Leu", + "ISO4217": "498" + }, + "MGA": { + "symbol": "MGA", + "name": "Malagasy Ariary", + "ISO4217": "969" + }, + "MKD": { + "symbol": "ден", + "name": "Macedonian Denar", + "ISO4217": "807" + }, + "MMK": { + "symbol": "Ks", + "name": "Myanmar Kyat", + "ISO4217": "104" + }, + "MNT": { + "symbol": "₮", + "name": "Mongolian Tugrik", + "ISO4217": "496" + }, + "MOP": { + "symbol": "MOP$", + "name": "Macau Pataca", + "ISO4217": "446" + }, + "MRO": { + "symbol": "UM", + "name": "Mauritania Ougulya", + "decimals": 0, + "retired": true, + "retirementDate": "2018-07-11", + "ISO4217": "478" + }, + "MRU": { + "symbol": "UM", + "name": "Mauritania Ougulya", + "decimals": 0, + "ISO4217": "" + }, + "MUR": { + "symbol": "Rs", + "name": "Mauritius Rupee", + "ISO4217": "480" + }, + "MVR": { + "symbol": "Rf", + "name": "Maldives Rufiyaa", + "ISO4217": "462" + }, + "MWK": { + "symbol": "MK", + "name": "Malawi Kwacha", + "ISO4217": "454" + }, + "MXN": { + "symbol": "Mex$", + "name": "Mexican Peso", + "ISO4217": "484" + }, + "MYR": { + "symbol": "RM", + "name": "Malaysian Ringgit", + "ISO4217": "458" + }, + "MZN": { + "symbol": "MTn", + "name": "Mozambican Metical", + "ISO4217": "943" + }, + "NAD": { + "symbol": "N$", + "name": "Namibian Dollar", + "ISO4217": "516" + }, + "NGN": { + "symbol": "₦", + "name": "Nigerian Naira", + "ISO4217": "566" + }, + "NIO": { + "symbol": "NIO", + "name": "Nicaragua Cordoba", + "ISO4217": "558" + }, + "NOK": { + "symbol": "Nkr", + "name": "Norwegian Krone", + "ISO4217": "578" + }, + "NPR": { + "symbol": "₨", + "name": "Nepalese Rupee", + "ISO4217": "524" + }, + "NZD": { + "symbol": "NZ$", + "name": "New Zealand Dollar", + "ISO4217": "554" + }, + "OMR": { + "symbol": "OMR", + "name": "Omani Rial", + "ISO4217": "512" + }, + "PAB": { + "symbol": "B", + "name": "Panama Balboa", + "ISO4217": "590" + }, + "PEN": { + "symbol": "S/.", + "name": "Peruvian Nuevo Sol", + "ISO4217": "604" + }, + "PGK": { + "symbol": "K", + "name": "Papua New Guinea Kina", + "ISO4217": "598" + }, + "PHP": { + "symbol": "₱", + "name": "Philippine Peso", + "ISO4217": "608" + }, + "PKR": { + "symbol": "Rs", + "name": "Pakistani Rupee", + "ISO4217": "586" + }, + "PLN": { + "symbol": "zł", + "name": "Polish Zloty", + "ISO4217": "985" + }, + "PYG": { + "symbol": "₲", + "name": "Paraguayan Guarani", + "ISO4217": "600" + }, + "QAR": { + "symbol": "QAR", + "name": "Qatar Rial", + "ISO4217": "634" + }, + "RON": { + "symbol": "RON", + "name": "Romanian New Leu", + "ISO4217": "946" + }, + "RSD": { + "symbol": "РСД", + "name": "Serbian Dinar", + "ISO4217": "941" + }, + "RUB": { + "symbol": "₽", + "name": "Russian Rouble", + "ISO4217": "643" + }, + "RWF": { + "symbol": "RF", + "name": "Rwanda Franc", + "decimals": 0, + "ISO4217": "646" + }, + "SAR": { + "symbol": "SAR", + "name": "Saudi Arabian Riyal", + "ISO4217": "682" + }, + "SBD": { + "symbol": "SI$", + "name": "Solomon Islands Dollar", + "ISO4217": "090" + }, + "SCR": { + "symbol": "SR", + "name": "Seychelles Rupee", + "ISO4217": "690" + }, + "SDG": { + "symbol": "SDG", + "name": "Sudanese Pound", + "ISO4217": "938" + }, + "SEK": { + "symbol": "Skr", + "name": "Swedish Krona", + "ISO4217": "752" + }, + "SGD": { + "symbol": "S$", + "name": "Singapore Dollar", + "ISO4217": "702" + }, + "SHP": { + "symbol": "£S", + "name": "St Helena Pound", + "ISO4217": "654" + }, + "SLL": { + "symbol": "Le", + "name": "Sierra Leone Leone", + "ISO4217": "694" + }, + "SOS": { + "symbol": "So.", + "name": "Somali Shilling", + "ISO4217": "706" + }, + "SRD": { + "symbol": "SRD", + "name": "Surinamese Dollar", + "ISO4217": "968" + }, + "STD": { + "symbol": "Db", + "name": "Sao Tome Dobra", + "retired": true, + "retirementDate": "2018-07-11", + "ISO4217": "678" + }, + "STN": { + "symbol": "Db", + "name": "Sao Tome Dobra", + "ISO4217": "" + }, + "SVC": { + "symbol": "SVC", + "name": "El Salvador Colon", + "ISO4217": "222" + }, + "SYP": { + "symbol": "SYP", + "name": "Syrian Pound", + "ISO4217": "760" + }, + "SZL": { + "symbol": "E", + "name": "Swaziland Lilageni", + "ISO4217": "748" + }, + "THB": { + "symbol": "฿", + "name": "Thai Baht", + "ISO4217": "764" + }, + "TJS": { + "symbol": "TJS", + "name": "Tajikistani Somoni", + "ISO4217": "972" + }, + "TMT": { + "symbol": "m", + "name": "Turkmenistani Manat", + "ISO4217": "934" + }, + "TND": { + "symbol": "TND", + "name": "Tunisian Dinar", + "ISO4217": "788" + }, + "TOP": { + "symbol": "T$", + "name": "Tonga Pa'ang", + "ISO4217": "776" + }, + "TRY": { + "symbol": "TL", + "name": "Turkish Lira", + "ISO4217": "949" + }, + "TTD": { + "symbol": "TT$", + "name": "Trinidad & Tobago Dollar", + "ISO4217": "780" + }, + "TWD": { + "symbol": "NT$", + "name": "Taiwan Dollar", + "ISO4217": "901" + }, + "TZS": { + "symbol": "TZS", + "name": "Tanzanian Shilling", + "ISO4217": "834" + }, + "UAH": { + "symbol": "₴", + "name": "Ukraine Hryvnia", + "ISO4217": "980" + }, + "UGX": { + "symbol": "USh", + "name": "Ugandan Shilling", + "decimals": 0, + "ISO4217": "800" + }, + "USD": { + "symbol": "$", + "name": "United States Dollar", + "ISO4217": "840" + }, + "UYU": { + "symbol": "$U", + "name": "Uruguayan New Peso", + "ISO4217": "858" + }, + "UZS": { + "symbol": "UZS", + "name": "Uzbekistani Som", + "ISO4217": "860" + }, + "VEB": { + "symbol": "Bs.", + "name": "Venezuelan Bolivar", + "retired": true, + "retirementDate": "2008-02-01", + "ISO4217": "" + }, + "VEF": { + "symbol": "Bs.F", + "name": "Venezuelan Bolivar Fuerte", + "retired": true, + "retirementDate": "2018-08-20", + "ISO4217": "937" + }, + "VES": { + "symbol": "Bs.S", + "name": "Venezuelan Bolivar Soberano", + "ISO4217": "928" + }, + "VND": { + "symbol": "₫", + "name": "Vietnam Dong", + "decimals": 0, + "ISO4217": "704" + }, + "VUV": { + "symbol": "Vt", + "name": "Vanuatu Vatu", + "ISO4217": "548" + }, + "WST": { + "symbol": "WS$", + "name": "Samoa Tala", + "ISO4217": "882" + }, + "XAF": { + "symbol": "FCFA", + "name": "CFA Franc (BEAC)", + "decimals": 0, + "ISO4217": "950" + }, + "XCD": { + "symbol": "EC$", + "name": "East Caribbean Dollar", + "ISO4217": "951" + }, + "XOF": { + "symbol": "CFA", + "name": "CFA Franc (BCEAO)", + "decimals": 0, + "ISO4217": "952" + }, + "XPF": { + "symbol": "XPF", + "name": "Pacific Franc", + "decimals": 0, + "ISO4217": "953" + }, + "YER": { + "symbol": "YER", + "name": "Yemen Riyal", + "ISO4217": "886" + }, + "ZAR": { + "symbol": "R", + "name": "South African Rand", + "ISO4217": "710" + }, + "ZMK": { + "symbol": "ZK", + "name": "Zambian Kwacha", + "retired": true, + "retirementDate": "2013-01-01", + "ISO4217": "894" + }, + "ZMW": { + "symbol": "ZMW", + "name": "Zambian Kwacha", + "cacheBurst": 1, + "ISO4217": "967" + } +} + \ No newline at end of file From 155dc0216fdab5354c2f1fe1348e7d24f4055a2b Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Fri, 1 Apr 2022 14:14:54 +0530 Subject: [PATCH 08/27] test: replace require to import --- tests/unit/CurrencySymbolUtilsTest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/CurrencySymbolUtilsTest.js b/tests/unit/CurrencySymbolUtilsTest.js index ff3ec6772d3..483c1f2decf 100644 --- a/tests/unit/CurrencySymbolUtilsTest.js +++ b/tests/unit/CurrencySymbolUtilsTest.js @@ -1,4 +1,4 @@ -const _ = require('underscore'); +import _ from 'underscore'; import * as CurrencySymbolUtils from '../../src/libs/CurrencySymbolUtils'; import currencyList from './currencyList.json'; From 3e57e26e43b3671189b1408f872e04c59baa7f56 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Fri, 1 Apr 2022 14:21:29 +0530 Subject: [PATCH 09/27] test: fix lint error --- tests/unit/CurrencySymbolUtilsTest.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/CurrencySymbolUtilsTest.js b/tests/unit/CurrencySymbolUtilsTest.js index 483c1f2decf..0a01eb0e0c8 100644 --- a/tests/unit/CurrencySymbolUtilsTest.js +++ b/tests/unit/CurrencySymbolUtilsTest.js @@ -12,7 +12,6 @@ const symbolPositions = [ [false, 'es', 'USD'] ]; - describe('CurrencySymbolUtils', () => { describe('getLocalizedCurrencySymbol', () => { From 6a0e40069caeb9b456bb8ff0d5f942acfbea97ff Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Fri, 1 Apr 2022 14:27:27 +0530 Subject: [PATCH 10/27] test: fix lint error --- tests/unit/CurrencySymbolUtilsTest.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unit/CurrencySymbolUtilsTest.js b/tests/unit/CurrencySymbolUtilsTest.js index 0a01eb0e0c8..ae38925aa2c 100644 --- a/tests/unit/CurrencySymbolUtilsTest.js +++ b/tests/unit/CurrencySymbolUtilsTest.js @@ -9,12 +9,11 @@ const AVAILABLE_LOCALES = ['en', 'es']; // Contains item [isLeft, locale, currencyCode] const symbolPositions = [ [true, 'en', 'USD'], - [false, 'es', 'USD'] + [false, 'es', 'USD'], ]; describe('CurrencySymbolUtils', () => { describe('getLocalizedCurrencySymbol', () => { - test.each(AVAILABLE_LOCALES)('returns non empty string for all currencyCode with preferredLocale %s', (prefrredLocale) => { _.forEach(currencyCodeList, (currencyCode) => { const localizedSymbol = CurrencySymbolUtils.getLocalizedCurrencySymbol(prefrredLocale, currencyCode); @@ -26,7 +25,6 @@ describe('CurrencySymbolUtils', () => { }); describe('isCurrencySymbolLTR', () => { - test.each(symbolPositions)('returns %s for prefrredLocale %s and currencyCode %s', (isLeft, locale, currencyCode) => { const isSymbolLeft = CurrencySymbolUtils.isCurrencySymbolLTR(locale, currencyCode); expect(isSymbolLeft).toBe(isLeft); From 84bcdeb341633c44c81334d8caac138e1064d8ea Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Fri, 1 Apr 2022 15:26:25 +0530 Subject: [PATCH 11/27] refactor: CurrencySymbolUtils --- src/libs/CurrencySymbolUtils.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libs/CurrencySymbolUtils.js b/src/libs/CurrencySymbolUtils.js index 86d28dda2e1..6bcdb1a5f9b 100644 --- a/src/libs/CurrencySymbolUtils.js +++ b/src/libs/CurrencySymbolUtils.js @@ -12,8 +12,7 @@ function getLocalizedCurrencySymbol(preferredLocale, currencyCode) { style: 'currency', currency: currencyCode, }); - const currencySymbol = _.find(parts, part => part.type === 'currency').value; - return currencySymbol; + return _.find(parts, part => part.type === 'currency').value; } /** @@ -31,8 +30,7 @@ function isCurrencySymbolLTR(preferredLocale, currencyCode) { // The first element of parts will be type: currency for all currency // Where it starts with symbol and the other will have it at last // If it is not the first, it must be at last - const isLeft = parts[0].type === 'currency'; - return isLeft; + return parts[0].type === 'currency'; } export { From 696b7d5dccb627df9a5f98d2658fb53f468089d3 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Fri, 1 Apr 2022 15:35:30 +0530 Subject: [PATCH 12/27] test: refactor names --- tests/unit/CurrencySymbolUtilsTest.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/unit/CurrencySymbolUtilsTest.js b/tests/unit/CurrencySymbolUtilsTest.js index ae38925aa2c..4f4a2994b9e 100644 --- a/tests/unit/CurrencySymbolUtilsTest.js +++ b/tests/unit/CurrencySymbolUtilsTest.js @@ -3,7 +3,6 @@ import * as CurrencySymbolUtils from '../../src/libs/CurrencySymbolUtils'; import currencyList from './currencyList.json'; const currencyCodeList = _.keys(currencyList); - const AVAILABLE_LOCALES = ['en', 'es']; // Contains item [isLeft, locale, currencyCode] @@ -14,18 +13,17 @@ const symbolPositions = [ describe('CurrencySymbolUtils', () => { describe('getLocalizedCurrencySymbol', () => { - test.each(AVAILABLE_LOCALES)('returns non empty string for all currencyCode with preferredLocale %s', (prefrredLocale) => { + test.each(AVAILABLE_LOCALES)('Returns non empty string for all currencyCode with preferredLocale %s', (prefrredLocale) => { _.forEach(currencyCodeList, (currencyCode) => { const localizedSymbol = CurrencySymbolUtils.getLocalizedCurrencySymbol(prefrredLocale, currencyCode); - expect(typeof localizedSymbol).toBe('string'); - expect(localizedSymbol.length).toBeGreaterThan(0); + expect(localizedSymbol).toBeTruthy(); }); }); }); describe('isCurrencySymbolLTR', () => { - test.each(symbolPositions)('returns %s for prefrredLocale %s and currencyCode %s', (isLeft, locale, currencyCode) => { + test.each(symbolPositions)('Returns %s for prefrredLocale %s and currencyCode %s', (isLeft, locale, currencyCode) => { const isSymbolLeft = CurrencySymbolUtils.isCurrencySymbolLTR(locale, currencyCode); expect(isSymbolLeft).toBe(isLeft); }); From 3ef60e8703b71b794e9a96df2837b24edb7b6ba9 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Fri, 1 Apr 2022 15:39:14 +0530 Subject: [PATCH 13/27] docs: update comments --- src/libs/CurrencySymbolUtils.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/CurrencySymbolUtils.js b/src/libs/CurrencySymbolUtils.js index 6bcdb1a5f9b..e535af20a35 100644 --- a/src/libs/CurrencySymbolUtils.js +++ b/src/libs/CurrencySymbolUtils.js @@ -2,10 +2,10 @@ import _ from 'underscore'; import * as NumberFormatUtils from './NumberFormatUtils'; /** - * Get localized currency symbol for SO4217 Code + * Get localized currency symbol for currency(ISO 4217) Code * @param {String} preferredLocale * @param {String} currencyCode - * @return {String} + * @returns {String} */ function getLocalizedCurrencySymbol(preferredLocale, currencyCode) { const parts = NumberFormatUtils.formatToParts(preferredLocale, 0, { @@ -16,10 +16,10 @@ function getLocalizedCurrencySymbol(preferredLocale, currencyCode) { } /** - * Is currency symbol to left + * Whether the currency symbol is left-to-right. * @param {String} preferredLocale * @param {String} currencyCode - * @return {Boolean} + * @returns {Boolean} */ function isCurrencySymbolLTR(preferredLocale, currencyCode) { const parts = NumberFormatUtils.formatToParts(preferredLocale, 0, { From 5992dfc74e665866451d7256157e4c0e303f027b Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Fri, 1 Apr 2022 21:52:08 +0530 Subject: [PATCH 14/27] docs: update comment --- src/libs/CurrencySymbolUtils.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libs/CurrencySymbolUtils.js b/src/libs/CurrencySymbolUtils.js index e535af20a35..bbe37939fd1 100644 --- a/src/libs/CurrencySymbolUtils.js +++ b/src/libs/CurrencySymbolUtils.js @@ -27,9 +27,7 @@ function isCurrencySymbolLTR(preferredLocale, currencyCode) { currency: currencyCode, }); - // The first element of parts will be type: currency for all currency - // Where it starts with symbol and the other will have it at last - // If it is not the first, it must be at last + // Currency is LTR when the first part is of currency type. return parts[0].type === 'currency'; } From 671f2d206eb0f86744fb1f0aeaa0ad5718524b4b Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Tue, 10 May 2022 17:36:27 +0530 Subject: [PATCH 15/27] add comment for currencyList.json --- tests/unit/CurrencySymbolUtilsTest.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/unit/CurrencySymbolUtilsTest.js b/tests/unit/CurrencySymbolUtilsTest.js index 4f4a2994b9e..0fa69dd7494 100644 --- a/tests/unit/CurrencySymbolUtilsTest.js +++ b/tests/unit/CurrencySymbolUtilsTest.js @@ -1,3 +1,9 @@ +// currencyList can get outdated, you can get the latest list from server +// src/libs/API.js +// GetCurrencyList().then(data => console.log(data.currencyList)); +// it will output the json in console, you can copy it and use any external json formatter +// finally update currencyList.json + import _ from 'underscore'; import * as CurrencySymbolUtils from '../../src/libs/CurrencySymbolUtils'; import currencyList from './currencyList.json'; @@ -29,3 +35,4 @@ describe('CurrencySymbolUtils', () => { }); }); }); + From 7c4aa7e3aa647f75469ce0d572ce51f77a3d6636 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Tue, 10 May 2022 20:53:45 +0530 Subject: [PATCH 16/27] refactor: IOUAmountPage --- src/components/AmountTextInput.js | 45 +++++++++++++++ src/components/CurrencySymbolButton.js | 23 ++++++++ src/components/TextInputWithCurrencySymbol.js | 55 +++++++++++++++++++ src/pages/iou/steps/IOUAmountPage.js | 40 ++++---------- 4 files changed, 135 insertions(+), 28 deletions(-) create mode 100644 src/components/AmountTextInput.js create mode 100644 src/components/CurrencySymbolButton.js create mode 100644 src/components/TextInputWithCurrencySymbol.js diff --git a/src/components/AmountTextInput.js b/src/components/AmountTextInput.js new file mode 100644 index 00000000000..304e79d0bfe --- /dev/null +++ b/src/components/AmountTextInput.js @@ -0,0 +1,45 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import TextInput from './TextInput'; +import styles from '../styles/styles'; +import CONST from '../CONST'; + +const propTypes = { + formattedAmount: PropTypes.string.isRequired, + forwardedRef: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.shape({current: PropTypes.instanceOf(React.Component)}), + ]), + onChangeAmount: PropTypes.func.isRequired, + placeholder: PropTypes.string.isRequired, +}; + +const defaultProps = { + forwardedRef: undefined, +}; + +function AmountTextInput(props) { + return ( + + ); +} + +AmountTextInput.propTypes = propTypes; +AmountTextInput.defaultProps = defaultProps; +AmountTextInput.displayName = 'AmountTextInput'; + +export default React.forwardRef((props, ref) => ( + // eslint-disable-next-line react/jsx-props-no-spreading + +)); diff --git a/src/components/CurrencySymbolButton.js b/src/components/CurrencySymbolButton.js new file mode 100644 index 00000000000..46e8fab1a04 --- /dev/null +++ b/src/components/CurrencySymbolButton.js @@ -0,0 +1,23 @@ +import React from 'react'; +import {TouchableOpacity} from 'react-native'; +import PropTypes from 'prop-types'; +import Text from './Text'; +import styles from '../styles/styles'; + +const propTypes = { + currencySymbol: PropTypes.string.isRequired, + onCurrencyButtonPress: PropTypes.func.isRequired, +}; + +function CurrencySymbolButton(props) { + return ( + + {props.currencySymbol} + + ); +} + +CurrencySymbolButton.propTypes = propTypes; +CurrencySymbolButton.displayName = 'CurrencySymbolButton'; + +export default CurrencySymbolButton; diff --git a/src/components/TextInputWithCurrencySymbol.js b/src/components/TextInputWithCurrencySymbol.js new file mode 100644 index 00000000000..27063188d37 --- /dev/null +++ b/src/components/TextInputWithCurrencySymbol.js @@ -0,0 +1,55 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import AmountTextInput from './AmountTextInput'; +import CurrencySymbolButton from './CurrencySymbolButton'; + +const propTypes = { + currencySymbol: PropTypes.string.isRequired, + forwardedRef: PropTypes.oneOfType([ + PropTypes.func, + PropTypes.shape({current: PropTypes.instanceOf(React.Component)}), + ]), + formattedAmount: PropTypes.string.isRequired, + isCurrencySymbolLTR: PropTypes.bool, + onChangeAmount: PropTypes.func, + onCurrencyButtonPress: PropTypes.func, + placeholder: PropTypes.string.isRequired, +}; + +const defaultProps = { + forwardedRef: undefined, + isCurrencySymbolLTR: true, + onChangeAmount: () => {}, + onCurrencyButtonPress: () => {}, +}; + +function TextInputWithCurrencySymbol(props) { + const currencySymbolButton = ( + + ); + + const amountTextInput = ( + + ); + + return props.isCurrencySymbolLTR + ? [currencySymbolButton, amountTextInput] + : [amountTextInput, currencySymbolButton]; +} + +TextInputWithCurrencySymbol.propTypes = propTypes; +TextInputWithCurrencySymbol.defaultProps = defaultProps; +TextInputWithCurrencySymbol.displayName = 'TextInputWithCurrencySymbol'; + +export default React.forwardRef((props, ref) => ( + // eslint-disable-next-line react/jsx-props-no-spreading + +)); diff --git a/src/pages/iou/steps/IOUAmountPage.js b/src/pages/iou/steps/IOUAmountPage.js index d15911b19e5..38999874184 100755 --- a/src/pages/iou/steps/IOUAmountPage.js +++ b/src/pages/iou/steps/IOUAmountPage.js @@ -1,7 +1,6 @@ import React from 'react'; import { View, - TouchableOpacity, InteractionManager, } from 'react-native'; import PropTypes from 'prop-types'; @@ -16,11 +15,10 @@ import ROUTES from '../../../ROUTES'; import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize'; import compose from '../../../libs/compose'; import Button from '../../../components/Button'; -import Text from '../../../components/Text'; import CONST from '../../../CONST'; -import TextInput from '../../../components/TextInput'; import canUseTouchScreen from '../../../libs/canUseTouchscreen'; import * as CurrencySymbolUtils from '../../../libs/CurrencySymbolUtils'; +import TextInputWithCurrencySymbol from '../../../components/TextInputWithCurrencySymbol'; const propTypes = { /** Whether or not this IOU has multiple participants */ @@ -210,30 +208,6 @@ class IOUAmountPage extends React.Component { const currencySymbol = CurrencySymbolUtils.getLocalizedCurrencySymbol(this.props.preferredLocale, this.props.iou.selectedCurrencyCode); const isCurrencySymbolLTR = CurrencySymbolUtils.isCurrencySymbolLTR(this.props.preferredLocale, this.props.iou.selectedCurrencyCode); - const currencySymbolElement = ( - Navigation.navigate(this.props.hasMultipleParticipants - ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) - : ROUTES.getIouRequestCurrencyRoute(this.props.reportID))} - > - {currencySymbol} - - ); - - const amountTextInput = ( - this.textInput = el} - value={formattedAmount} - placeholder={this.props.numberFormat(0)} - keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} - /> - ); - return ( <> - {isCurrencySymbolLTR ? [currencySymbolElement, amountTextInput] : [amountTextInput, currencySymbolElement]} + Navigation.navigate(this.props.hasMultipleParticipants + ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) + : ROUTES.getIouRequestCurrencyRoute(this.props.reportID))} + placeholder={this.props.numberFormat(0)} + ref={el => this.textInput = el} + /> {canUseTouchScreen() From 291782f5ae7a0eb4c52d1b3eec6a6fa09fd34d04 Mon Sep 17 00:00:00 2001 From: mdneyazahmad <77761491+mdneyazahmad@users.noreply.github.com> Date: Thu, 12 May 2022 21:03:00 +0530 Subject: [PATCH 17/27] update comment in tests/unit/CurrencySymbolUtilsTest.js Co-authored-by: Rajat Parashar --- tests/unit/CurrencySymbolUtilsTest.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/unit/CurrencySymbolUtilsTest.js b/tests/unit/CurrencySymbolUtilsTest.js index 0fa69dd7494..d2967bae3ae 100644 --- a/tests/unit/CurrencySymbolUtilsTest.js +++ b/tests/unit/CurrencySymbolUtilsTest.js @@ -1,8 +1,4 @@ -// currencyList can get outdated, you can get the latest list from server -// src/libs/API.js -// GetCurrencyList().then(data => console.log(data.currencyList)); -// it will output the json in console, you can copy it and use any external json formatter -// finally update currencyList.json +// Taken from GetCurrencyList API. import _ from 'underscore'; import * as CurrencySymbolUtils from '../../src/libs/CurrencySymbolUtils'; From 184102246a478ed484ad4c51cd36922ef7a4b925 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Thu, 12 May 2022 21:19:44 +0530 Subject: [PATCH 18/27] refactor: TextInputWithCurrencySymbol --- src/components/TextInputWithCurrencySymbol.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/components/TextInputWithCurrencySymbol.js b/src/components/TextInputWithCurrencySymbol.js index 27063188d37..b2ab33573ea 100644 --- a/src/components/TextInputWithCurrencySymbol.js +++ b/src/components/TextInputWithCurrencySymbol.js @@ -40,9 +40,21 @@ function TextInputWithCurrencySymbol(props) { /> ); - return props.isCurrencySymbolLTR - ? [currencySymbolButton, amountTextInput] - : [amountTextInput, currencySymbolButton]; + if (props.isCurrencySymbolLTR) { + return ( + <> + {currencySymbolButton} + {amountTextInput} + + ); + } + + return ( + <> + {amountTextInput} + {currencySymbolButton} + + ); } TextInputWithCurrencySymbol.propTypes = propTypes; From 6147523e22cc65356542a2fcd50654eef2915d74 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Thu, 12 May 2022 21:25:06 +0530 Subject: [PATCH 19/27] refactor: move inline function to class method --- src/pages/iou/steps/IOUAmountPage.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/pages/iou/steps/IOUAmountPage.js b/src/pages/iou/steps/IOUAmountPage.js index 38999874184..d879e337c07 100755 --- a/src/pages/iou/steps/IOUAmountPage.js +++ b/src/pages/iou/steps/IOUAmountPage.js @@ -63,6 +63,7 @@ class IOUAmountPage extends React.Component { this.stripCommaFromAmount = this.stripCommaFromAmount.bind(this); this.focusTextInput = this.focusTextInput.bind(this); this.focusEmptyInput = this.focusEmptyInput.bind(this); + this.navigateToCurrencySelectionPage = this.navigateToCurrencySelectionPage.bind(this); this.state = { amount: props.selectedAmount, @@ -203,6 +204,12 @@ class IOUAmountPage extends React.Component { .value(); } + navigateToCurrencySelectionPage() { + Navigation.navigate(this.props.hasMultipleParticipants + ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) + : ROUTES.getIouRequestCurrencyRoute(this.props.reportID)); + } + render() { const formattedAmount = this.replaceAllDigits(this.state.amount, this.props.toLocaleDigit); const currencySymbol = CurrencySymbolUtils.getLocalizedCurrencySymbol(this.props.preferredLocale, this.props.iou.selectedCurrencyCode); @@ -223,9 +230,7 @@ class IOUAmountPage extends React.Component { formattedAmount={formattedAmount} isCurrencySymbolLTR={isCurrencySymbolLTR} onChangeAmount={this.updateAmount} - onCurrencyButtonPress={() => Navigation.navigate(this.props.hasMultipleParticipants - ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) - : ROUTES.getIouRequestCurrencyRoute(this.props.reportID))} + onCurrencyButtonPress={this.navigateToCurrencySelectionPage} placeholder={this.props.numberFormat(0)} ref={el => this.textInput = el} /> From 8e9764f1336a5a307481c44654920751a1d96a7f Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Thu, 12 May 2022 21:38:13 +0530 Subject: [PATCH 20/27] refactor: IOUAmountPage --- src/components/TextInputWithCurrencySymbol.js | 13 ++++++++----- src/pages/iou/steps/IOUAmountPage.js | 7 ++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/components/TextInputWithCurrencySymbol.js b/src/components/TextInputWithCurrencySymbol.js index b2ab33573ea..2d4b88fedf6 100644 --- a/src/components/TextInputWithCurrencySymbol.js +++ b/src/components/TextInputWithCurrencySymbol.js @@ -2,31 +2,34 @@ import React from 'react'; import PropTypes from 'prop-types'; import AmountTextInput from './AmountTextInput'; import CurrencySymbolButton from './CurrencySymbolButton'; +import * as CurrencySymbolUtils from '../libs/CurrencySymbolUtils'; const propTypes = { - currencySymbol: PropTypes.string.isRequired, forwardedRef: PropTypes.oneOfType([ PropTypes.func, PropTypes.shape({current: PropTypes.instanceOf(React.Component)}), ]), formattedAmount: PropTypes.string.isRequired, - isCurrencySymbolLTR: PropTypes.bool, onChangeAmount: PropTypes.func, onCurrencyButtonPress: PropTypes.func, placeholder: PropTypes.string.isRequired, + preferredLocale: PropTypes.string.isRequired, + selectedCurrencyCode: PropTypes.string.isRequired, }; const defaultProps = { forwardedRef: undefined, - isCurrencySymbolLTR: true, onChangeAmount: () => {}, onCurrencyButtonPress: () => {}, }; function TextInputWithCurrencySymbol(props) { + const currencySymbol = CurrencySymbolUtils.getLocalizedCurrencySymbol(props.preferredLocale, props.selectedCurrencyCode); + const isCurrencySymbolLTR = CurrencySymbolUtils.isCurrencySymbolLTR(props.preferredLocale, props.selectedCurrencyCode); + const currencySymbolButton = ( ); @@ -40,7 +43,7 @@ function TextInputWithCurrencySymbol(props) { /> ); - if (props.isCurrencySymbolLTR) { + if (isCurrencySymbolLTR) { return ( <> {currencySymbolButton} diff --git a/src/pages/iou/steps/IOUAmountPage.js b/src/pages/iou/steps/IOUAmountPage.js index d879e337c07..8589f431c68 100755 --- a/src/pages/iou/steps/IOUAmountPage.js +++ b/src/pages/iou/steps/IOUAmountPage.js @@ -17,7 +17,6 @@ import compose from '../../../libs/compose'; import Button from '../../../components/Button'; import CONST from '../../../CONST'; import canUseTouchScreen from '../../../libs/canUseTouchscreen'; -import * as CurrencySymbolUtils from '../../../libs/CurrencySymbolUtils'; import TextInputWithCurrencySymbol from '../../../components/TextInputWithCurrencySymbol'; const propTypes = { @@ -212,8 +211,6 @@ class IOUAmountPage extends React.Component { render() { const formattedAmount = this.replaceAllDigits(this.state.amount, this.props.toLocaleDigit); - const currencySymbol = CurrencySymbolUtils.getLocalizedCurrencySymbol(this.props.preferredLocale, this.props.iou.selectedCurrencyCode); - const isCurrencySymbolLTR = CurrencySymbolUtils.isCurrencySymbolLTR(this.props.preferredLocale, this.props.iou.selectedCurrencyCode); return ( <> @@ -226,13 +223,13 @@ class IOUAmountPage extends React.Component { ]} > this.textInput = el} + selectedCurrencyCode={this.props.iou.selectedCurrencyCode} /> From 46148a3882592c64d7a81fed69d07e4c2af75601 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Thu, 12 May 2022 22:07:12 +0530 Subject: [PATCH 21/27] docs: add jsdocs --- src/components/AmountTextInput.js | 7 +++++++ src/components/CurrencySymbolButton.js | 3 +++ src/components/TextInputWithCurrencySymbol.js | 13 +++++++++++++ 3 files changed, 23 insertions(+) diff --git a/src/components/AmountTextInput.js b/src/components/AmountTextInput.js index 304e79d0bfe..2182f3a8903 100644 --- a/src/components/AmountTextInput.js +++ b/src/components/AmountTextInput.js @@ -5,12 +5,19 @@ import styles from '../styles/styles'; import CONST from '../CONST'; const propTypes = { + /** Formatted amount in local currency */ formattedAmount: PropTypes.string.isRequired, + + /** A ref to forward to amount text input */ forwardedRef: PropTypes.oneOfType([ PropTypes.func, PropTypes.shape({current: PropTypes.instanceOf(React.Component)}), ]), + + /** Function to call when amount in text input is changed */ onChangeAmount: PropTypes.func.isRequired, + + /** Placeholder value for amount text input */ placeholder: PropTypes.string.isRequired, }; diff --git a/src/components/CurrencySymbolButton.js b/src/components/CurrencySymbolButton.js index 46e8fab1a04..85a6ad8e408 100644 --- a/src/components/CurrencySymbolButton.js +++ b/src/components/CurrencySymbolButton.js @@ -5,7 +5,10 @@ import Text from './Text'; import styles from '../styles/styles'; const propTypes = { + /** Currency symbol of selected currency */ currencySymbol: PropTypes.string.isRequired, + + /** Function to call when currency button is pressed */ onCurrencyButtonPress: PropTypes.func.isRequired, }; diff --git a/src/components/TextInputWithCurrencySymbol.js b/src/components/TextInputWithCurrencySymbol.js index 2d4b88fedf6..4bbc2ee5b9e 100644 --- a/src/components/TextInputWithCurrencySymbol.js +++ b/src/components/TextInputWithCurrencySymbol.js @@ -5,15 +5,28 @@ import CurrencySymbolButton from './CurrencySymbolButton'; import * as CurrencySymbolUtils from '../libs/CurrencySymbolUtils'; const propTypes = { + /** A ref to forward to amount text input */ forwardedRef: PropTypes.oneOfType([ PropTypes.func, PropTypes.shape({current: PropTypes.instanceOf(React.Component)}), ]), + + /** Formatted amount in local currency */ formattedAmount: PropTypes.string.isRequired, + + /** Function to call when amount in text input is changed */ onChangeAmount: PropTypes.func, + + /** Function to call when currency button is pressed */ onCurrencyButtonPress: PropTypes.func, + + /** Placeholder value for amount text input */ placeholder: PropTypes.string.isRequired, + + /** Preferred locale of the user */ preferredLocale: PropTypes.string.isRequired, + + /** Currency code of user's selected currency */ selectedCurrencyCode: PropTypes.string.isRequired, }; From f85bbdea2d49e60d3b0578daef4f2bae3b312140 Mon Sep 17 00:00:00 2001 From: mdneyazahmad <77761491+mdneyazahmad@users.noreply.github.com> Date: Tue, 17 May 2022 16:25:05 +0530 Subject: [PATCH 22/27] style: format code Co-authored-by: Rajat Parashar --- src/pages/iou/steps/IOUAmountPage.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/steps/IOUAmountPage.js b/src/pages/iou/steps/IOUAmountPage.js index 8589f431c68..d85d42d76c3 100755 --- a/src/pages/iou/steps/IOUAmountPage.js +++ b/src/pages/iou/steps/IOUAmountPage.js @@ -204,9 +204,11 @@ class IOUAmountPage extends React.Component { } navigateToCurrencySelectionPage() { - Navigation.navigate(this.props.hasMultipleParticipants + Navigation.navigate( + this.props.hasMultipleParticipants ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) - : ROUTES.getIouRequestCurrencyRoute(this.props.reportID)); + : ROUTES.getIouRequestCurrencyRoute(this.props.reportID) + ); } render() { From 355e65d377bbb69519dfef620e5291cc9132b6cd Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Tue, 17 May 2022 17:37:29 +0530 Subject: [PATCH 23/27] refactor: remove unused code --- src/pages/iou/steps/IOUAmountPage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/iou/steps/IOUAmountPage.js b/src/pages/iou/steps/IOUAmountPage.js index fdac934536d..29a8e5cc3b2 100755 --- a/src/pages/iou/steps/IOUAmountPage.js +++ b/src/pages/iou/steps/IOUAmountPage.js @@ -61,7 +61,6 @@ class IOUAmountPage extends React.Component { this.updateAmount = this.updateAmount.bind(this); this.stripCommaFromAmount = this.stripCommaFromAmount.bind(this); this.focusTextInput = this.focusTextInput.bind(this); - this.focusEmptyInput = this.focusEmptyInput.bind(this); this.navigateToCurrencySelectionPage = this.navigateToCurrencySelectionPage.bind(this); this.state = { From c25bf6457b8398cce1d194ddb404c57426501dc9 Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Tue, 17 May 2022 17:53:00 +0530 Subject: [PATCH 24/27] style: fix eslint error --- src/pages/iou/steps/IOUAmountPage.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/iou/steps/IOUAmountPage.js b/src/pages/iou/steps/IOUAmountPage.js index 36cd7ee68b8..ad4060ee8f7 100755 --- a/src/pages/iou/steps/IOUAmountPage.js +++ b/src/pages/iou/steps/IOUAmountPage.js @@ -194,10 +194,10 @@ class IOUAmountPage extends React.Component { navigateToCurrencySelectionPage() { Navigation.navigate( - this.props.hasMultipleParticipants - ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) - : ROUTES.getIouRequestCurrencyRoute(this.props.reportID) - ); + this.props.hasMultipleParticipants + ? ROUTES.getIouBillCurrencyRoute(this.props.reportID) + : ROUTES.getIouRequestCurrencyRoute(this.props.reportID), + ); } render() { From 133a62e84981b23257951baa9c0152d63fecde2e Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Tue, 17 May 2022 18:02:50 +0530 Subject: [PATCH 25/27] chore: update comment --- tests/unit/CurrencySymbolUtilsTest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/CurrencySymbolUtilsTest.js b/tests/unit/CurrencySymbolUtilsTest.js index d2967bae3ae..4c89b473cae 100644 --- a/tests/unit/CurrencySymbolUtilsTest.js +++ b/tests/unit/CurrencySymbolUtilsTest.js @@ -1,7 +1,7 @@ -// Taken from GetCurrencyList API. - import _ from 'underscore'; import * as CurrencySymbolUtils from '../../src/libs/CurrencySymbolUtils'; + +// Taken from GetCurrencyList API. import currencyList from './currencyList.json'; const currencyCodeList = _.keys(currencyList); From f018a244b0b8d7d1345ca2c564a5428ac6cae492 Mon Sep 17 00:00:00 2001 From: mdneyazahmad <77761491+mdneyazahmad@users.noreply.github.com> Date: Thu, 2 Jun 2022 22:48:09 +0530 Subject: [PATCH 26/27] test: fix typo Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- tests/unit/CurrencySymbolUtilsTest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/CurrencySymbolUtilsTest.js b/tests/unit/CurrencySymbolUtilsTest.js index 4c89b473cae..48742e7e87f 100644 --- a/tests/unit/CurrencySymbolUtilsTest.js +++ b/tests/unit/CurrencySymbolUtilsTest.js @@ -25,7 +25,7 @@ describe('CurrencySymbolUtils', () => { }); describe('isCurrencySymbolLTR', () => { - test.each(symbolPositions)('Returns %s for prefrredLocale %s and currencyCode %s', (isLeft, locale, currencyCode) => { + test.each(symbolPositions)('Returns %s for preferredLocale %s and currencyCode %s', (isLeft, locale, currencyCode) => { const isSymbolLeft = CurrencySymbolUtils.isCurrencySymbolLTR(locale, currencyCode); expect(isSymbolLeft).toBe(isLeft); }); From c93b4cb8d3354addd5f2f8a289a80ea639a40a8a Mon Sep 17 00:00:00 2001 From: Md Neyaz Ahmad Date: Thu, 2 Jun 2022 23:24:37 +0530 Subject: [PATCH 27/27] test: update comment --- tests/unit/CurrencySymbolUtilsTest.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/unit/CurrencySymbolUtilsTest.js b/tests/unit/CurrencySymbolUtilsTest.js index 48742e7e87f..dc072a03fae 100644 --- a/tests/unit/CurrencySymbolUtilsTest.js +++ b/tests/unit/CurrencySymbolUtilsTest.js @@ -1,7 +1,11 @@ import _ from 'underscore'; import * as CurrencySymbolUtils from '../../src/libs/CurrencySymbolUtils'; -// Taken from GetCurrencyList API. +// This file can get outdated. In that case, you can follow these steps to update it: +// - in src/libs/API.js +// - call: GetCurrencyList().then(data => console.log(data.currencyList)); +// - copy the json from console and format it to valid json using some external tool +// - update currencyList.json import currencyList from './currencyList.json'; const currencyCodeList = _.keys(currencyList);