From 1c4d9cfe506916b5f6c20f5afd01ab2354a5e417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Mon, 5 Jun 2023 11:29:29 +0200 Subject: [PATCH 001/100] migrated AddReactionBubble to PressableWithoutFeedback --- src/components/Reactions/AddReactionBubble.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/Reactions/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.js index 7704ee4c25c4..f6423c4cc862 100644 --- a/src/components/Reactions/AddReactionBubble.js +++ b/src/components/Reactions/AddReactionBubble.js @@ -1,5 +1,5 @@ import React, {useRef} from 'react'; -import {Pressable, View} from 'react-native'; +import {View} from 'react-native'; import PropTypes from 'prop-types'; import Tooltip from '../Tooltip'; import styles from '../../styles/styles'; @@ -12,6 +12,7 @@ import * as EmojiPickerAction from '../../libs/actions/EmojiPickerAction'; import variables from '../../styles/variables'; import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import * as Session from '../../libs/actions/Session'; +import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback'; const propTypes = { /** Whether it is for context menu so we can modify its style */ @@ -68,12 +69,14 @@ const AddReactionBubble = (props) => { return ( - [styles.emojiReactionBubble, styles.userSelectNone, StyleUtils.getEmojiReactionBubbleStyle(hovered || pressed, false, props.isContextMenu)]} onPress={Session.checkIfActionIsAllowed(onPress)} // Prevent text input blur when Add reaction is clicked onMouseDown={(e) => e.preventDefault()} + accessibilityLabel={props.translate('emojiReactions.addReactionTooltip')} + accessibilityRole="button" > {({hovered, pressed}) => ( <> @@ -91,7 +94,7 @@ const AddReactionBubble = (props) => { )} - + ); }; From 895cf5e6380c58bfe9df38add2cdf1cc28cb8379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Mon, 5 Jun 2023 12:51:08 +0200 Subject: [PATCH 002/100] changed PressableWithFeedback to be able to change icon color on hover etc --- src/components/Pressable/PressableWithFeedback.js | 2 +- src/components/Reactions/AddReactionBubble.js | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/Pressable/PressableWithFeedback.js b/src/components/Pressable/PressableWithFeedback.js index 281492568867..44ef8694582c 100644 --- a/src/components/Pressable/PressableWithFeedback.js +++ b/src/components/Pressable/PressableWithFeedback.js @@ -73,7 +73,7 @@ const PressableWithFeedback = forwardRef((props, ref) => { ...(state.focused ? StyleUtils.parseStyleAsArray(props.focusStyle, state) : []), ]} > - {props.children} + {_.isFunction(props.children) ? props.children(state) : props.children} )} diff --git a/src/components/Reactions/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.js index f6423c4cc862..4996bd9af8e4 100644 --- a/src/components/Reactions/AddReactionBubble.js +++ b/src/components/Reactions/AddReactionBubble.js @@ -12,7 +12,7 @@ import * as EmojiPickerAction from '../../libs/actions/EmojiPickerAction'; import variables from '../../styles/variables'; import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import * as Session from '../../libs/actions/Session'; -import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback'; +import PressableWithFeedback from '../Pressable/PressableWithFeedback'; const propTypes = { /** Whether it is for context menu so we can modify its style */ @@ -69,7 +69,7 @@ const AddReactionBubble = (props) => { return ( - [styles.emojiReactionBubble, styles.userSelectNone, StyleUtils.getEmojiReactionBubbleStyle(hovered || pressed, false, props.isContextMenu)]} onPress={Session.checkIfActionIsAllowed(onPress)} @@ -77,6 +77,7 @@ const AddReactionBubble = (props) => { onMouseDown={(e) => e.preventDefault()} accessibilityLabel={props.translate('emojiReactions.addReactionTooltip')} accessibilityRole="button" + hoverDimmingValue={1} > {({hovered, pressed}) => ( <> @@ -94,7 +95,7 @@ const AddReactionBubble = (props) => { )} - + ); }; From 77fd23fe0bfd0a01a2f6d7c347f4f14a5f4e2775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Mon, 5 Jun 2023 12:55:33 +0200 Subject: [PATCH 003/100] disabled dimming --- src/components/Reactions/AddReactionBubble.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/Reactions/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.js index 4996bd9af8e4..ecf63bd87747 100644 --- a/src/components/Reactions/AddReactionBubble.js +++ b/src/components/Reactions/AddReactionBubble.js @@ -77,7 +77,9 @@ const AddReactionBubble = (props) => { onMouseDown={(e) => e.preventDefault()} accessibilityLabel={props.translate('emojiReactions.addReactionTooltip')} accessibilityRole="button" + // disable dimming hoverDimmingValue={1} + pressDimmingValue={1} > {({hovered, pressed}) => ( <> From cd4de9f9a7224ec6f024a2f255f46877b6837658 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Tue, 6 Jun 2023 00:16:44 +0100 Subject: [PATCH 004/100] [Refactor] AdditionalDetailsStep - Return Error keys from Form validation method --- .../EnablePayments/AdditionalDetailsStep.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.js b/src/pages/EnablePayments/AdditionalDetailsStep.js index e7cfbfc3ab67..4a99c6409edf 100644 --- a/src/pages/EnablePayments/AdditionalDetailsStep.js +++ b/src/pages/EnablePayments/AdditionalDetailsStep.js @@ -124,47 +124,47 @@ class AdditionalDetailsStep extends React.Component { const errors = {}; if (_.isEmpty(values[INPUT_IDS.LEGAL_FIRST_NAME])) { - errors[INPUT_IDS.LEGAL_FIRST_NAME] = this.props.translate(this.errorTranslationKeys.legalFirstName); + errors[INPUT_IDS.LEGAL_FIRST_NAME] = this.errorTranslationKeys.legalFirstName; } if (_.isEmpty(values[INPUT_IDS.LEGAL_LAST_NAME])) { - errors[INPUT_IDS.LEGAL_LAST_NAME] = this.props.translate(this.errorTranslationKeys.legalLastName); + errors[INPUT_IDS.LEGAL_LAST_NAME] = this.errorTranslationKeys.legalLastName; } if (!ValidationUtils.isValidPastDate(values[INPUT_IDS.DOB]) || !ValidationUtils.meetsMaximumAgeRequirement(values[INPUT_IDS.DOB])) { - ErrorUtils.addErrorMessage(errors, INPUT_IDS.DOB, this.props.translate(this.errorTranslationKeys.dob)); + ErrorUtils.addErrorMessage(errors, INPUT_IDS.DOB, this.errorTranslationKeys.dob); } else if (!ValidationUtils.meetsMinimumAgeRequirement(values[INPUT_IDS.DOB])) { - ErrorUtils.addErrorMessage(errors, INPUT_IDS.DOB, this.props.translate(this.errorTranslationKeys.age)); + ErrorUtils.addErrorMessage(errors, INPUT_IDS.DOB, this.errorTranslationKeys.age); } if (!ValidationUtils.isValidAddress(values[INPUT_IDS.ADDRESS.street]) || _.isEmpty(values[INPUT_IDS.ADDRESS.street])) { - errors[INPUT_IDS.ADDRESS.street] = this.props.translate('bankAccount.error.addressStreet'); + errors[INPUT_IDS.ADDRESS.street] = 'bankAccount.error.addressStreet'; } if (_.isEmpty(values[INPUT_IDS.ADDRESS.city])) { - errors[INPUT_IDS.ADDRESS.city] = this.props.translate('bankAccount.error.addressCity'); + errors[INPUT_IDS.ADDRESS.city] = 'bankAccount.error.addressCity'; } if (_.isEmpty(values[INPUT_IDS.ADDRESS.state])) { - errors[INPUT_IDS.ADDRESS.state] = this.props.translate('bankAccount.error.addressState'); + errors[INPUT_IDS.ADDRESS.state] = 'bankAccount.error.addressState'; } if (!ValidationUtils.isValidZipCode(values[INPUT_IDS.ADDRESS.zipCode])) { - errors[INPUT_IDS.ADDRESS.zipCode] = this.props.translate('bankAccount.error.zipCode'); + errors[INPUT_IDS.ADDRESS.zipCode] = 'bankAccount.error.zipCode'; } if (!ValidationUtils.isValidUSPhone(values[INPUT_IDS.PHONE_NUMBER], true)) { - errors[INPUT_IDS.PHONE_NUMBER] = this.props.translate(this.errorTranslationKeys.phoneNumber); + errors[INPUT_IDS.PHONE_NUMBER] = this.errorTranslationKeys.phoneNumber; } // this.props.walletAdditionalDetails stores errors returned by the server. If the server returns an SSN error // then the user needs to provide the full 9 digit SSN. if (this.props.walletAdditionalDetails.errorCode === CONST.WALLET.ERROR.SSN) { if (!ValidationUtils.isValidSSNFullNine(values[INPUT_IDS.SSN])) { - errors[INPUT_IDS.SSN] = this.props.translate(this.errorTranslationKeys.ssnFull9); + errors[INPUT_IDS.SSN] = this.errorTranslationKeys.ssnFull9; } } else if (!ValidationUtils.isValidSSNLastFour(values[INPUT_IDS.SSN])) { - errors[INPUT_IDS.SSN] = this.props.translate(this.errorTranslationKeys.ssn); + errors[INPUT_IDS.SSN] = this.errorTranslationKeys.ssn; } return errors; From 34e75325641892a0a29f2f416dfd6303af342f5a Mon Sep 17 00:00:00 2001 From: Robert Kozik Date: Tue, 6 Jun 2023 13:07:36 +0200 Subject: [PATCH 005/100] migrate BaseMiniContextMenuItem to PressableWithoutFeedback --- src/components/BaseMiniContextMenuItem.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/BaseMiniContextMenuItem.js b/src/components/BaseMiniContextMenuItem.js index 47e6ab6cd7dd..55475b770aac 100644 --- a/src/components/BaseMiniContextMenuItem.js +++ b/src/components/BaseMiniContextMenuItem.js @@ -1,4 +1,4 @@ -import {Pressable, View} from 'react-native'; +import {View} from 'react-native'; import React from 'react'; import PropTypes from 'prop-types'; import _ from 'underscore'; @@ -7,6 +7,7 @@ import * as StyleUtils from '../styles/StyleUtils'; import getButtonState from '../libs/getButtonState'; import variables from '../styles/variables'; import Tooltip from './Tooltip'; +import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; const propTypes = { /** @@ -48,9 +49,8 @@ const defaultProps = { */ const BaseMiniContextMenuItem = (props) => ( - [ @@ -63,7 +63,7 @@ const BaseMiniContextMenuItem = (props) => ( {_.isFunction(props.children) ? props.children(pressableState) : props.children} )} - + ); From bed5eadd21a1b4c91287aa7999aa6eedae34e3d4 Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Tue, 6 Jun 2023 22:41:41 +0530 Subject: [PATCH 006/100] refactor ReportActionItemMessageEdit to functional component --- .../report/ReportActionItemMessageEdit.js | 466 +++++++++--------- 1 file changed, 231 insertions(+), 235 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index 602425f4c0c8..ad349076ba55 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -1,6 +1,6 @@ /* eslint-disable rulesdir/onyx-props-must-have-default */ import lodashGet from 'lodash/get'; -import React from 'react'; +import React, {useState, useRef, useMemo, useEffect, useCallback} from 'react'; // eslint-disable-next-line no-restricted-imports import {InteractionManager, Keyboard, Pressable, TouchableOpacity, View} from 'react-native'; import PropTypes from 'prop-types'; @@ -74,315 +74,311 @@ const defaultProps = { preferredSkinTone: CONST.EMOJI_DEFAULT_SKIN_TONE, }; -class ReportActionItemMessageEdit extends React.Component { - constructor(props) { - super(props); - this.updateDraft = this.updateDraft.bind(this); - this.deleteDraft = this.deleteDraft.bind(this); - this.debouncedSaveDraft = _.debounce(this.debouncedSaveDraft.bind(this), 1000); - this.publishDraft = this.publishDraft.bind(this); - this.triggerSaveOrCancel = this.triggerSaveOrCancel.bind(this); - this.onSelectionChange = this.onSelectionChange.bind(this); - this.addEmojiToTextBox = this.addEmojiToTextBox.bind(this); - this.setExceededMaxCommentLength = this.setExceededMaxCommentLength.bind(this); - this.saveButtonID = 'saveButton'; - this.cancelButtonID = 'cancelButton'; - this.emojiButtonID = 'emojiButton'; - this.messageEditInput = 'messageEditInput'; - - let draftMessage; - if (this.props.draftMessage === this.props.action.message[0].html) { +function ReportActionItemMessageEdit(props) { + const {action, draftMessage, forwardedRef, index, isKeyboardShown, isSmallScreenWidth, preferredSkinTone, reportID, shouldDisableEmojiPicker, translate} = props; + + const [draft, setDraft] = useState(() => { + if (draftMessage === action.message[0].html) { // We only convert the report action message to markdown if the draft message is unchanged. const parser = new ExpensiMark(); - draftMessage = parser.htmlToMarkdown(this.props.draftMessage).trim(); - } else { - // We need to decode saved draft message because it's escaped before saving. - draftMessage = Str.htmlDecode(this.props.draftMessage); + return parser.htmlToMarkdown(draftMessage).trim(); } - - this.state = { - draft: draftMessage, - selection: { - start: 0, - end: 0, - }, - isFocused: false, - hasExceededMaxCommentLength: false, - }; - } - - componentDidMount() { + // We need to decode saved draft message because it's escaped before saving. + return Str.htmlDecode(draftMessage); + }); + const [selection, setSelection] = useState({start: 0, end: 0}); + const [isFocused, setIsFocused] = useState(false); + const [hasExceededMaxCommentLength, setHasExceededMaxCommentLength] = useState(false); + + const textInputRef = useRef(null); + + // native ids + const saveButtonID = 'saveButton'; + const cancelButtonID = 'cancelButton'; + const emojiButtonID = 'emojiButton'; + const messageEditInput = 'messageEditInput'; + + useEffect(() => { // For mobile Safari, updating the selection prop on an unfocused input will cause it to automatically gain focus // and subsequent programmatic focus shifts (e.g., modal focus trap) to show the blue frame (:focus-visible style), // so we need to ensure that it is only updated after focus. - this.setState((prevState) => ({ - selection: { - start: prevState.draft.length, - end: prevState.draft.length, - }, - })); - } - - componentWillUnmount() { - // Skip if this is not the focused message so the other edit composer stays focused. - if (!this.state.isFocused) { - return; - } + setDraft((prevDraft) => { + setSelection({ + start: prevDraft.length, + end: prevDraft.length, + }); + return prevDraft; + }); + }, []); - // Show the main composer when the focused message is deleted from another client - // to prevent the main composer stays hidden until we swtich to another chat. - ComposerActions.setShouldShowComposeInput(true); - } + useEffect( + () => () => { + // Skip if this is not the focused message so the other edit composer stays focused. + if (!isFocused) { + return; + } + + // Show the main composer when the focused message is deleted from another client + // to prevent the main composer stays hidden until we swtich to another chat. + ComposerActions.setShouldShowComposeInput(true); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps -- for willUnmount lifecycle + [], + ); /** * Update Selection on change cursor position. * * @param {Event} e */ - onSelectionChange(e) { - this.setState({selection: e.nativeEvent.selection}); - } + const onSelectionChange = useCallback((e) => { + setSelection(e.nativeEvent.selection); + }, []); /** * Updates the composer when the comment length is exceeded * Shows red borders and prevents the comment from being sent * - * @param {Boolean} hasExceededMaxCommentLength + * @param {Boolean} hasExceeded */ - setExceededMaxCommentLength(hasExceededMaxCommentLength) { - this.setState({hasExceededMaxCommentLength}); - } + const setExceededMaxCommentLength = useCallback((hasExceeded) => { + setHasExceededMaxCommentLength(hasExceeded); + }, []); + + /** + * Save the draft of the comment. This debounced so that we're not ceaselessly saving your edit. Saving the draft + * allows one to navigate somewhere else and come back to the comment and still have it in edit mode. + * @param {String} newDraft + */ + const debouncedSaveDraft = useMemo( + () => + _.debounce((newDraft) => { + Report.saveReportActionDraft(reportID, action.reportActionID, newDraft); + }, 1000), + [reportID, action.reportActionID], + ); /** * Update the value of the draft in Onyx * - * @param {String} draft + * @param {String} newDraftValue */ - updateDraft(draft) { - const {text: newDraft = '', emojis = []} = EmojiUtils.replaceEmojis(draft, this.props.isSmallScreenWidth, this.props.preferredSkinTone); - - if (!_.isEmpty(emojis)) { - User.updateFrequentlyUsedEmojis(EmojiUtils.getFrequentlyUsedEmojis(emojis)); - } + const updateDraft = useCallback( + (newDraftValue) => { + const {text: newDraft = '', emojis = []} = EmojiUtils.replaceEmojis(newDraftValue, isSmallScreenWidth, preferredSkinTone); - this.setState((prevState) => { - const newState = {draft: newDraft}; - if (draft !== newDraft) { - const remainder = prevState.draft.slice(prevState.selection.end).length; - newState.selection = { - start: newDraft.length - remainder, - end: newDraft.length - remainder, - }; + if (!_.isEmpty(emojis)) { + User.updateFrequentlyUsedEmojis(EmojiUtils.getFrequentlyUsedEmojis(emojis)); } - return newState; - }); - - // This component is rendered only when draft is set to a non-empty string. In order to prevent component - // unmount when user deletes content of textarea, we set previous message instead of empty string. - if (newDraft.trim().length > 0) { - // We want to escape the draft message to differentiate the HTML from the report action and the HTML the user drafted. - this.debouncedSaveDraft(_.escape(newDraft)); - } else { - this.debouncedSaveDraft(this.props.action.message[0].html); - } - } + if (newDraftValue !== newDraft) { + setSelection((prevSelection) => { + const remainder = draft.slice(prevSelection.end).length; + return { + start: newDraft.length - remainder, + end: newDraft.length - remainder, + }; + }); + } + setDraft(newDraft); + + // This component is rendered only when draft is set to a non-empty string. In order to prevent component + // unmount when user deletes content of textarea, we set previous message instead of empty string. + if (newDraft.trim().length > 0) { + // We want to escape the draft message to differentiate the HTML from the report action and the HTML the user drafted. + debouncedSaveDraft(_.escape(newDraft)); + } else { + debouncedSaveDraft(action.message[0].html); + } + }, + [action.message, draft, debouncedSaveDraft, isSmallScreenWidth, preferredSkinTone], + ); /** * Delete the draft of the comment being edited. This will take the comment out of "edit mode" with the old content. */ - deleteDraft() { - this.debouncedSaveDraft.cancel(); - Report.saveReportActionDraft(this.props.reportID, this.props.action.reportActionID, ''); + const deleteDraft = useCallback(() => { + debouncedSaveDraft.cancel(); + Report.saveReportActionDraft(reportID, action.reportActionID, ''); ComposerActions.setShouldShowComposeInput(true); ReportActionComposeFocusManager.focus(); // Scroll to the last comment after editing to make sure the whole comment is clearly visible in the report. - if (this.props.index === 0) { + if (index === 0) { const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => { - ReportScrollManager.scrollToIndex({animated: true, index: this.props.index}, false); + ReportScrollManager.scrollToIndex({animated: true, index}, false); keyboardDidHideListener.remove(); }); } - } - - /** - * Save the draft of the comment. This debounced so that we're not ceaselessly saving your edit. Saving the draft - * allows one to navigate somewhere else and come back to the comment and still have it in edit mode. - * @param {String} newDraft - */ - debouncedSaveDraft(newDraft) { - Report.saveReportActionDraft(this.props.reportID, this.props.action.reportActionID, newDraft); - } + }, [action.reportActionID, debouncedSaveDraft, index, reportID]); /** * Save the draft of the comment to be the new comment message. This will take the comment out of "edit mode" with * the new content. */ - publishDraft() { + const publishDraft = useCallback(() => { // Do nothing if draft exceed the character limit - if (ReportUtils.getCommentLength(this.state.draft) > CONST.MAX_COMMENT_LENGTH) { + if (ReportUtils.getCommentLength(draft) > CONST.MAX_COMMENT_LENGTH) { return; } // To prevent re-mount after user saves edit before debounce duration (example: within 1 second), we cancel // debounce here. - this.debouncedSaveDraft.cancel(); + debouncedSaveDraft.cancel(); - const trimmedNewDraft = this.state.draft.trim(); + const trimmedNewDraft = draft.trim(); // When user tries to save the empty message, it will delete it. Prompt the user to confirm deleting. if (!trimmedNewDraft) { - ReportActionContextMenu.showDeleteModal(this.props.reportID, this.props.action, false, this.deleteDraft, () => - InteractionManager.runAfterInteractions(() => this.textInput.focus()), - ); + ReportActionContextMenu.showDeleteModal(reportID, action, false, deleteDraft, () => InteractionManager.runAfterInteractions(() => textInputRef.current.focus())); return; } - Report.editReportComment(this.props.reportID, this.props.action, trimmedNewDraft); - this.deleteDraft(); - } + Report.editReportComment(reportID, action, trimmedNewDraft); + deleteDraft(); + }, [action, debouncedSaveDraft, deleteDraft, draft, reportID]); /** * @param {String} emoji */ - addEmojiToTextBox(emoji) { - this.setState((prevState) => ({ - selection: { - start: prevState.selection.start + emoji.length, - end: prevState.selection.start + emoji.length, - }, - })); - this.updateDraft(ComposerUtils.insertText(this.state.draft, this.state.selection, emoji)); - } + const addEmojiToTextBox = useCallback( + (emoji) => { + setSelection((prevSelection) => ({ + start: prevSelection.start + emoji.length, + end: prevSelection.start + emoji.length, + })); + updateDraft(ComposerUtils.insertText(draft, selection, emoji)); + }, + [draft, selection, updateDraft], + ); /** * Key event handlers that short cut to saving/canceling. * * @param {Event} e */ - triggerSaveOrCancel(e) { - if (!e || ComposerUtils.canSkipTriggerHotkeys(this.props.isSmallScreenWidth, this.props.isKeyboardShown)) { - return; - } - if (e.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey && !e.shiftKey) { - e.preventDefault(); - this.publishDraft(); - } else if (e.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey) { - e.preventDefault(); - this.deleteDraft(); - } - } - - render() { - const hasExceededMaxCommentLength = this.state.hasExceededMaxCommentLength; - return ( - <> - - - - [styles.chatItemSubmitButton, StyleUtils.getButtonBackgroundColorStyle(getButtonState(hovered, pressed))]} - nativeID={this.cancelButtonID} - onPress={this.deleteDraft} + const triggerSaveOrCancel = useCallback( + (e) => { + if (!e || ComposerUtils.canSkipTriggerHotkeys(isSmallScreenWidth, isKeyboardShown)) { + return; + } + if (e.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey && !e.shiftKey) { + e.preventDefault(); + publishDraft(); + } else if (e.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey) { + e.preventDefault(); + deleteDraft(); + } + }, + [deleteDraft, isKeyboardShown, isSmallScreenWidth, publishDraft], + ); + + return ( + <> + + + + [styles.chatItemSubmitButton, StyleUtils.getButtonBackgroundColorStyle(getButtonState(hovered, pressed))]} + nativeID={cancelButtonID} + onPress={deleteDraft} + hitSlop={{ + top: 3, + right: 3, + bottom: 3, + left: 3, + }} + > + {({hovered, pressed}) => ( + + )} + + + + + + { + textInputRef.current = el; + forwardedRef.current = el; + }} + nativeID={messageEditInput} + onChangeText={updateDraft} // Debounced saveDraftComment + onKeyPress={triggerSaveOrCancel} + value={draft} + maxLines={isSmallScreenWidth ? CONST.COMPOSER.MAX_LINES_SMALL_SCREEN : CONST.COMPOSER.MAX_LINES} // This is the same that slack has + style={[styles.textInputCompose, styles.flex1, styles.bgTransparent]} + onFocus={() => { + setIsFocused(true); + ReportScrollManager.scrollToIndex({animated: true, index}, true); + ComposerActions.setShouldShowComposeInput(false); + }} + onBlur={(event) => { + setIsFocused(false); + const relatedTargetId = lodashGet(event, 'nativeEvent.relatedTarget.id'); + + // Return to prevent re-render when save/cancel button is pressed which cancels the onPress event by re-rendering + if (_.contains([saveButtonID, cancelButtonID, emojiButtonID], relatedTargetId)) { + return; + } + + if (messageEditInput === relatedTargetId) { + return; + } + openReportActionComposeViewWhenClosingMessageEdit(); + }} + selection={selection} + onSelectionChange={onSelectionChange} + /> + + + InteractionManager.runAfterInteractions(() => textInputRef.current.focus())} + onEmojiSelected={addEmojiToTextBox} + nativeID={emojiButtonID} + /> + + + + + - {({hovered, pressed}) => ( - - )} - + + - - - { - this.textInput = el; - this.props.forwardedRef.current = el; - }} - nativeID={this.messageEditInput} - onChangeText={this.updateDraft} // Debounced saveDraftComment - onKeyPress={this.triggerSaveOrCancel} - value={this.state.draft} - maxLines={this.props.isSmallScreenWidth ? CONST.COMPOSER.MAX_LINES_SMALL_SCREEN : CONST.COMPOSER.MAX_LINES} // This is the same that slack has - style={[styles.textInputCompose, styles.flex1, styles.bgTransparent]} - onFocus={() => { - this.setState({isFocused: true}); - ReportScrollManager.scrollToIndex({animated: true, index: this.props.index}, true); - ComposerActions.setShouldShowComposeInput(false); - }} - onBlur={(event) => { - this.setState({isFocused: false}); - const relatedTargetId = lodashGet(event, 'nativeEvent.relatedTarget.id'); - - // Return to prevent re-render when save/cancel button is pressed which cancels the onPress event by re-rendering - if (_.contains([this.saveButtonID, this.cancelButtonID, this.emojiButtonID], relatedTargetId)) { - return; - } - - if (this.messageEditInput === relatedTargetId) { - return; - } - openReportActionComposeViewWhenClosingMessageEdit(); - }} - selection={this.state.selection} - onSelectionChange={this.onSelectionChange} - /> - - - InteractionManager.runAfterInteractions(() => this.textInput.focus())} - onEmojiSelected={this.addEmojiToTextBox} - nativeID={this.emojiButtonID} - /> - - - - - - - - - - - - - ); - } + + + + ); } ReportActionItemMessageEdit.propTypes = propTypes; From a925dd61962155f26fc7b9057943ae5ed5a2cc7d Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Wed, 7 Jun 2023 08:31:05 +0530 Subject: [PATCH 007/100] moved functions to inline --- .../report/ReportActionItemMessageEdit.js | 35 +++++-------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index ad349076ba55..492b368430a4 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -74,6 +74,12 @@ const defaultProps = { preferredSkinTone: CONST.EMOJI_DEFAULT_SKIN_TONE, }; +// native ids +const saveButtonID = 'saveButton'; +const cancelButtonID = 'cancelButton'; +const emojiButtonID = 'emojiButton'; +const messageEditInput = 'messageEditInput'; + function ReportActionItemMessageEdit(props) { const {action, draftMessage, forwardedRef, index, isKeyboardShown, isSmallScreenWidth, preferredSkinTone, reportID, shouldDisableEmojiPicker, translate} = props; @@ -92,12 +98,6 @@ function ReportActionItemMessageEdit(props) { const textInputRef = useRef(null); - // native ids - const saveButtonID = 'saveButton'; - const cancelButtonID = 'cancelButton'; - const emojiButtonID = 'emojiButton'; - const messageEditInput = 'messageEditInput'; - useEffect(() => { // For mobile Safari, updating the selection prop on an unfocused input will cause it to automatically gain focus // and subsequent programmatic focus shifts (e.g., modal focus trap) to show the blue frame (:focus-visible style), @@ -126,25 +126,6 @@ function ReportActionItemMessageEdit(props) { [], ); - /** - * Update Selection on change cursor position. - * - * @param {Event} e - */ - const onSelectionChange = useCallback((e) => { - setSelection(e.nativeEvent.selection); - }, []); - - /** - * Updates the composer when the comment length is exceeded - * Shows red borders and prevents the comment from being sent - * - * @param {Boolean} hasExceeded - */ - const setExceededMaxCommentLength = useCallback((hasExceeded) => { - setHasExceededMaxCommentLength(hasExceeded); - }, []); - /** * Save the draft of the comment. This debounced so that we're not ceaselessly saving your edit. Saving the draft * allows one to navigate somewhere else and come back to the comment and still have it in edit mode. @@ -338,7 +319,7 @@ function ReportActionItemMessageEdit(props) { openReportActionComposeViewWhenClosingMessageEdit(); }} selection={selection} - onSelectionChange={onSelectionChange} + onSelectionChange={(e) => setSelection(e.nativeEvent.selection)} /> @@ -375,7 +356,7 @@ function ReportActionItemMessageEdit(props) { setHasExceededMaxCommentLength(hasExceeded)} /> ); From e7e59bfbf6b284cd05f8512b8cfd2d9977b4b321 Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Wed, 7 Jun 2023 08:37:56 +0530 Subject: [PATCH 008/100] moved to destructive props --- src/pages/home/report/ReportActionItemMessageEdit.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index 492b368430a4..f48c585376e5 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -80,9 +80,7 @@ const cancelButtonID = 'cancelButton'; const emojiButtonID = 'emojiButton'; const messageEditInput = 'messageEditInput'; -function ReportActionItemMessageEdit(props) { - const {action, draftMessage, forwardedRef, index, isKeyboardShown, isSmallScreenWidth, preferredSkinTone, reportID, shouldDisableEmojiPicker, translate} = props; - +function ReportActionItemMessageEdit({action, forwardedRef, draftMessage, index, isKeyboardShown, isSmallScreenWidth, preferredSkinTone, reportID, shouldDisableEmojiPicker, translate}) { const [draft, setDraft] = useState(() => { if (draftMessage === action.message[0].html) { // We only convert the report action message to markdown if the draft message is unchanged. @@ -291,6 +289,7 @@ function ReportActionItemMessageEdit(props) { multiline ref={(el) => { textInputRef.current = el; + // eslint-disable-next-line no-param-reassign forwardedRef.current = el; }} nativeID={messageEditInput} From bd25349d83f0647ea66d96997d91f030b971f834 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 07:30:25 +0100 Subject: [PATCH 009/100] [Refactor] WorkspaceRoom - Return Error keys from Form validation method --- src/pages/settings/Report/RoomNamePage.js | 10 +++++----- src/pages/workspace/WorkspaceNewRoomPage.js | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/pages/settings/Report/RoomNamePage.js b/src/pages/settings/Report/RoomNamePage.js index 0c51a8ab79f9..c1a1a5d2eba1 100644 --- a/src/pages/settings/Report/RoomNamePage.js +++ b/src/pages/settings/Report/RoomNamePage.js @@ -48,21 +48,21 @@ const RoomNamePage = (props) => { if (!values.roomName || values.roomName === CONST.POLICY.ROOM_PREFIX) { // We error if the user doesn't enter a room name or left blank - ErrorUtils.addErrorMessage(errors, 'roomName', translate('newRoomPage.pleaseEnterRoomName')); + ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.pleaseEnterRoomName'); } else if (!ValidationUtils.isValidRoomName(values.roomName)) { // We error if the room name has invalid characters - ErrorUtils.addErrorMessage(errors, 'roomName', translate('newRoomPage.roomNameInvalidError')); + ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomNameInvalidError'); } else if (ValidationUtils.isReservedRoomName(values.roomName)) { // Certain names are reserved for default rooms and should not be used for policy rooms. - ErrorUtils.addErrorMessage(errors, 'roomName', translate('newRoomPage.roomNameReservedError', {reservedName: values.roomName})); + ErrorUtils.addErrorMessage(errors, 'roomName', ['newRoomPage.roomNameReservedError', {reservedName: values.roomName}]); } else if (ValidationUtils.isExistingRoomName(values.roomName, reports, report.policyID)) { // The room name can't be set to one that already exists on the policy - ErrorUtils.addErrorMessage(errors, 'roomName', translate('newRoomPage.roomAlreadyExistsError')); + ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomAlreadyExistsError'); } return errors; }, - [report, reports, translate], + [report, reports], ); return ( diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index 6d19d2ae21b2..66dacfcd2666 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -101,16 +101,16 @@ class WorkspaceNewRoomPage extends React.Component { if (!values.roomName || values.roomName === CONST.POLICY.ROOM_PREFIX) { // We error if the user doesn't enter a room name or left blank - ErrorUtils.addErrorMessage(errors, 'roomName', this.props.translate('newRoomPage.pleaseEnterRoomName')); + ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.pleaseEnterRoomName'); } else if (values.roomName !== CONST.POLICY.ROOM_PREFIX && !ValidationUtils.isValidRoomName(values.roomName)) { // We error if the room name has invalid characters - ErrorUtils.addErrorMessage(errors, 'roomName', this.props.translate('newRoomPage.roomNameInvalidError')); + ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomNameInvalidError'); } else if (ValidationUtils.isReservedRoomName(values.roomName)) { // Certain names are reserved for default rooms and should not be used for policy rooms. - ErrorUtils.addErrorMessage(errors, 'roomName', this.props.translate('newRoomPage.roomNameReservedError', {reservedName: values.roomName})); + ErrorUtils.addErrorMessage(errors, 'roomName', ['newRoomPage.roomNameReservedError', {reservedName: values.roomName}]); } else if (ValidationUtils.isExistingRoomName(values.roomName, this.props.reports, values.policyID)) { // Certain names are reserved for default rooms and should not be used for policy rooms. - ErrorUtils.addErrorMessage(errors, 'roomName', this.props.translate('newRoomPage.roomAlreadyExistsError')); + ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomAlreadyExistsError'); } if (!values.policyID) { From 5f9a25b49c204d1e6af3c20fb62e3e5844f4385d Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 07:32:24 +0100 Subject: [PATCH 010/100] Accept array, as some errors has variables parameter --- src/libs/ErrorUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ErrorUtils.js b/src/libs/ErrorUtils.js index 03a26d8fa14c..e4f1b7bff877 100644 --- a/src/libs/ErrorUtils.js +++ b/src/libs/ErrorUtils.js @@ -91,7 +91,7 @@ function getLatestErrorField(onyxData, fieldName) { * Method used to generate error message for given inputID * @param {Object} errors - An object containing current errors in the form * @param {String} inputID - * @param {String} message - Message to assign to the inputID errors + * @param {String|Array} message - Message to assign to the inputID errors * */ function addErrorMessage(errors, inputID, message) { From a994180b6d6e20de01fc201576cc9960afe616d8 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 07:55:00 +0100 Subject: [PATCH 011/100] [Refactor] TaskTitle - Return Error keys from Form validation methods of different TaskTitle forms --- src/pages/tasks/NewTaskDetailsPage.js | 2 +- src/pages/tasks/NewTaskTitlePage.js | 2 +- src/pages/tasks/TaskTitlePage.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/tasks/NewTaskDetailsPage.js b/src/pages/tasks/NewTaskDetailsPage.js index 1d2a66be87e5..e0c6a57e1bcf 100644 --- a/src/pages/tasks/NewTaskDetailsPage.js +++ b/src/pages/tasks/NewTaskDetailsPage.js @@ -53,7 +53,7 @@ const NewTaskPage = (props) => { if (!values.taskTitle) { // We error if the user doesn't enter a task name - ErrorUtils.addErrorMessage(errors, 'taskTitle', props.translate('newTaskPage.pleaseEnterTaskName')); + ErrorUtils.addErrorMessage(errors, 'taskTitle', 'newTaskPage.pleaseEnterTaskName'); } return errors; diff --git a/src/pages/tasks/NewTaskTitlePage.js b/src/pages/tasks/NewTaskTitlePage.js index d2764b1a09b8..aae7830242d7 100644 --- a/src/pages/tasks/NewTaskTitlePage.js +++ b/src/pages/tasks/NewTaskTitlePage.js @@ -48,7 +48,7 @@ const NewTaskTitlePage = (props) => { if (!values.taskTitle) { // We error if the user doesn't enter a task name - ErrorUtils.addErrorMessage(errors, 'taskTitle', props.translate('newTaskPage.pleaseEnterTaskName')); + ErrorUtils.addErrorMessage(errors, 'taskTitle', 'newTaskPage.pleaseEnterTaskName'); } return errors; diff --git a/src/pages/tasks/TaskTitlePage.js b/src/pages/tasks/TaskTitlePage.js index cbeb9154f9fb..2f7a0f829b4d 100644 --- a/src/pages/tasks/TaskTitlePage.js +++ b/src/pages/tasks/TaskTitlePage.js @@ -47,12 +47,12 @@ function TaskTitlePage(props) { const errors = {}; if (_.isEmpty(values.title)) { - errors.title = props.translate('newTaskPage.pleaseEnterTaskName'); + errors.title = 'newTaskPage.pleaseEnterTaskName'; } return errors; }, - [props], + [], ); const submit = useCallback( From ec91a398da7630340e536f0c249843c9d340b51b Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 08:17:48 +0100 Subject: [PATCH 012/100] [Refactor] Personal details - Return Error keys from Form validation methods of different Personal details forms --- src/libs/ValidationUtils.js | 9 ++++----- src/pages/settings/Profile/DisplayNamePage.js | 6 +++--- .../settings/Profile/PersonalDetails/AddressPage.js | 10 +++++----- .../Profile/PersonalDetails/DateOfBirthPage.js | 4 ++-- .../settings/Profile/PersonalDetails/LegalNamePage.js | 11 +++++------ 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/libs/ValidationUtils.js b/src/libs/ValidationUtils.js index 7cefd11ec799..4778669840a8 100644 --- a/src/libs/ValidationUtils.js +++ b/src/libs/ValidationUtils.js @@ -5,7 +5,6 @@ import {parsePhoneNumber} from 'awesome-phonenumber'; import CONST from '../CONST'; import * as CardUtils from './CardUtils'; import * as LoginUtils from './LoginUtils'; -import * as Localize from './Localize'; /** * Implements the Luhn Algorithm, a checksum formula used to validate credit card @@ -225,22 +224,22 @@ function meetsMaximumAgeRequirement(date) { * @param {String} date * @param {Number} minimumAge * @param {Number} maximumAge - * @returns {String} + * @returns {String|Array} */ function getAgeRequirementError(date, minimumAge, maximumAge) { const recentDate = moment().startOf('day').subtract(minimumAge, 'years'); const longAgoDate = moment().startOf('day').subtract(maximumAge, 'years'); const testDate = moment(date); if (!testDate.isValid()) { - return Localize.translateLocal('common.error.dateInvalid'); + return 'common.error.dateInvalid'; } if (testDate.isBetween(longAgoDate, recentDate, undefined, '[]')) { return ''; } if (testDate.isSameOrAfter(recentDate)) { - return Localize.translateLocal('privatePersonalDetails.error.dateShouldBeBefore', {dateString: recentDate.format(CONST.DATE.MOMENT_FORMAT_STRING)}); + return ['privatePersonalDetails.error.dateShouldBeBefore', {dateString: recentDate.format(CONST.DATE.MOMENT_FORMAT_STRING)}]; } - return Localize.translateLocal('privatePersonalDetails.error.dateShouldBeAfter', {dateString: longAgoDate.format(CONST.DATE.MOMENT_FORMAT_STRING)}); + return ['privatePersonalDetails.error.dateShouldBeAfter', {dateString: longAgoDate.format(CONST.DATE.MOMENT_FORMAT_STRING)}]; } /** diff --git a/src/pages/settings/Profile/DisplayNamePage.js b/src/pages/settings/Profile/DisplayNamePage.js index e55d46fcb557..7ec8611983a7 100644 --- a/src/pages/settings/Profile/DisplayNamePage.js +++ b/src/pages/settings/Profile/DisplayNamePage.js @@ -56,15 +56,15 @@ class DisplayNamePage extends Component { // First we validate the first name field if (!ValidationUtils.isValidDisplayName(values.firstName)) { - ErrorUtils.addErrorMessage(errors, 'firstName', this.props.translate('personalDetails.error.hasInvalidCharacter')); + ErrorUtils.addErrorMessage(errors, 'firstName', 'personalDetails.error.hasInvalidCharacter'); } if (ValidationUtils.doesContainReservedWord(values.firstName, CONST.DISPLAY_NAME.RESERVED_FIRST_NAMES)) { - ErrorUtils.addErrorMessage(errors, 'firstName', this.props.translate('personalDetails.error.containsReservedWord')); + ErrorUtils.addErrorMessage(errors, 'firstName', 'personalDetails.error.containsReservedWord'); } // Then we validate the last name field if (!ValidationUtils.isValidDisplayName(values.lastName)) { - errors.lastName = this.props.translate('personalDetails.error.hasInvalidCharacter'); + errors.lastName = 'personalDetails.error.hasInvalidCharacter'; } return errors; diff --git a/src/pages/settings/Profile/PersonalDetails/AddressPage.js b/src/pages/settings/Profile/PersonalDetails/AddressPage.js index fcbfee12e251..8bd95d1df7c3 100644 --- a/src/pages/settings/Profile/PersonalDetails/AddressPage.js +++ b/src/pages/settings/Profile/PersonalDetails/AddressPage.js @@ -99,7 +99,7 @@ class AddressPage extends Component { // Check "State" dropdown is a valid state if selected Country is USA. if (this.state.isUsaForm && !COMMON_CONST.STATES[values.state]) { - errors.state = this.props.translate('common.error.fieldRequired'); + errors.state = 'common.error.fieldRequired'; } // Add "Field required" errors if any required field is empty @@ -107,7 +107,7 @@ class AddressPage extends Component { if (ValidationUtils.isRequiredFulfilled(values[fieldKey])) { return; } - errors[fieldKey] = this.props.translate('common.error.fieldRequired'); + errors[fieldKey] = 'common.error.fieldRequired'; }); // If no country is selected, default value is an empty string and there's no related regex data so we default to an empty object @@ -120,13 +120,13 @@ class AddressPage extends Component { if (countrySpecificZipRegex) { if (!countrySpecificZipRegex.test(values.zipPostCode.trim())) { if (ValidationUtils.isRequiredFulfilled(values.zipPostCode.trim())) { - errors.zipPostCode = this.props.translate('privatePersonalDetails.error.incorrectZipFormat', {zipFormat}); + errors.zipPostCode = ['privatePersonalDetails.error.incorrectZipFormat', {zipFormat}]; } else { - errors.zipPostCode = this.props.translate('common.error.fieldRequired'); + errors.zipPostCode = 'common.error.fieldRequired'; } } } else if (!CONST.GENERIC_ZIP_CODE_REGEX.test(values.zipPostCode.trim())) { - errors.zipPostCode = this.props.translate('privatePersonalDetails.error.incorrectZipFormat'); + errors.zipPostCode = 'privatePersonalDetails.error.incorrectZipFormat'; } return errors; diff --git a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js index 536462ce3e33..6a53d962a972 100644 --- a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js +++ b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js @@ -56,7 +56,7 @@ const DateOfBirthPage = ({translate, route, privatePersonalDetails}) => { const maximumAge = CONST.DATE_BIRTH.MAX_AGE; if (!values.dob || !ValidationUtils.isValidDate(values.dob)) { - errors.dob = translate('common.error.fieldRequired'); + errors.dob = 'common.error.fieldRequired'; } const dateError = ValidationUtils.getAgeRequirementError(values.dob, minimumAge, maximumAge); if (dateError) { @@ -65,7 +65,7 @@ const DateOfBirthPage = ({translate, route, privatePersonalDetails}) => { return errors; }, - [translate], + [], ); return ( diff --git a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js index 1ee9e60d93d8..f79ff963ec2a 100644 --- a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js +++ b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js @@ -44,27 +44,26 @@ const updateLegalName = (values) => { function LegalNamePage(props) { const legalFirstName = lodashGet(props.privatePersonalDetails, 'legalFirstName', ''); const legalLastName = lodashGet(props.privatePersonalDetails, 'legalLastName', ''); - const translate = props.translate; const validate = useCallback( (values) => { const errors = {}; if (!ValidationUtils.isValidLegalName(values.legalFirstName)) { - errors.legalFirstName = translate('privatePersonalDetails.error.hasInvalidCharacter'); + errors.legalFirstName = 'privatePersonalDetails.error.hasInvalidCharacter'; } else if (_.isEmpty(values.legalFirstName)) { - errors.legalFirstName = translate('common.error.fieldRequired'); + errors.legalFirstName = 'common.error.fieldRequired'; } if (!ValidationUtils.isValidLegalName(values.legalLastName)) { - errors.legalLastName = translate('privatePersonalDetails.error.hasInvalidCharacter'); + errors.legalLastName = 'privatePersonalDetails.error.hasInvalidCharacter'; } else if (_.isEmpty(values.legalLastName)) { - errors.legalLastName = translate('common.error.fieldRequired'); + errors.legalLastName = 'common.error.fieldRequired'; } return errors; }, - [translate], + [], ); return ( From 033daf777bb894916151f0bb9688d4deafee5d02 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 08:45:36 +0100 Subject: [PATCH 013/100] [Refactor] NewContactMethodPage - Return Error keys from Form validation method --- .../settings/Profile/Contacts/NewContactMethodPage.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/NewContactMethodPage.js b/src/pages/settings/Profile/Contacts/NewContactMethodPage.js index eae718349bd0..b39985ba0452 100644 --- a/src/pages/settings/Profile/Contacts/NewContactMethodPage.js +++ b/src/pages/settings/Profile/Contacts/NewContactMethodPage.js @@ -82,19 +82,19 @@ function NewContactMethodPage(props) { const errors = {}; if (_.isEmpty(values.phoneOrEmail)) { - ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', props.translate('contacts.genericFailureMessages.contactMethodRequired')); + ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', 'contacts.genericFailureMessages.contactMethodRequired'); } if (!_.isEmpty(values.phoneOrEmail) && !(parsePhoneNumber(phoneLogin).possible || Str.isValidEmail(values.phoneOrEmail))) { - ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', props.translate('contacts.genericFailureMessages.invalidContactMethod')); + ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', 'contacts.genericFailureMessages.invalidContactMethod'); } if (!_.isEmpty(values.phoneOrEmail) && lodashGet(props.loginList, validateIfnumber || values.phoneOrEmail.toLowerCase())) { - ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', props.translate('contacts.genericFailureMessages.enteredMethodIsAlreadySubmited')); + ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', 'contacts.genericFailureMessages.enteredMethodIsAlreadySubmited'); } if (!Permissions.canUsePasswordlessLogins(props.betas) && _.isEmpty(values.password)) { - errors.password = props.translate('contacts.genericFailureMessages.passwordRequired'); + errors.password = 'contacts.genericFailureMessages.passwordRequired'; } return errors; From fa7ad34ce414be1a652231faf8c908706ef9a3a8 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Tue, 6 Jun 2023 00:16:44 +0100 Subject: [PATCH 014/100] [Refactor] AdditionalDetailsStep - Return Error keys from Form validation method --- .../EnablePayments/AdditionalDetailsStep.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.js b/src/pages/EnablePayments/AdditionalDetailsStep.js index 22dd50e2ab4a..ac3d2ed43ea7 100644 --- a/src/pages/EnablePayments/AdditionalDetailsStep.js +++ b/src/pages/EnablePayments/AdditionalDetailsStep.js @@ -123,47 +123,47 @@ class AdditionalDetailsStep extends React.Component { const errors = {}; if (_.isEmpty(values[INPUT_IDS.LEGAL_FIRST_NAME])) { - errors[INPUT_IDS.LEGAL_FIRST_NAME] = this.props.translate(this.errorTranslationKeys.legalFirstName); + errors[INPUT_IDS.LEGAL_FIRST_NAME] = this.errorTranslationKeys.legalFirstName; } if (_.isEmpty(values[INPUT_IDS.LEGAL_LAST_NAME])) { - errors[INPUT_IDS.LEGAL_LAST_NAME] = this.props.translate(this.errorTranslationKeys.legalLastName); + errors[INPUT_IDS.LEGAL_LAST_NAME] = this.errorTranslationKeys.legalLastName; } if (!ValidationUtils.isValidPastDate(values[INPUT_IDS.DOB]) || !ValidationUtils.meetsMaximumAgeRequirement(values[INPUT_IDS.DOB])) { - ErrorUtils.addErrorMessage(errors, INPUT_IDS.DOB, this.props.translate(this.errorTranslationKeys.dob)); + ErrorUtils.addErrorMessage(errors, INPUT_IDS.DOB, this.errorTranslationKeys.dob); } else if (!ValidationUtils.meetsMinimumAgeRequirement(values[INPUT_IDS.DOB])) { - ErrorUtils.addErrorMessage(errors, INPUT_IDS.DOB, this.props.translate(this.errorTranslationKeys.age)); + ErrorUtils.addErrorMessage(errors, INPUT_IDS.DOB, this.errorTranslationKeys.age); } if (!ValidationUtils.isValidAddress(values[INPUT_IDS.ADDRESS.street]) || _.isEmpty(values[INPUT_IDS.ADDRESS.street])) { - errors[INPUT_IDS.ADDRESS.street] = this.props.translate('bankAccount.error.addressStreet'); + errors[INPUT_IDS.ADDRESS.street] = 'bankAccount.error.addressStreet'; } if (_.isEmpty(values[INPUT_IDS.ADDRESS.city])) { - errors[INPUT_IDS.ADDRESS.city] = this.props.translate('bankAccount.error.addressCity'); + errors[INPUT_IDS.ADDRESS.city] = 'bankAccount.error.addressCity'; } if (_.isEmpty(values[INPUT_IDS.ADDRESS.state])) { - errors[INPUT_IDS.ADDRESS.state] = this.props.translate('bankAccount.error.addressState'); + errors[INPUT_IDS.ADDRESS.state] = 'bankAccount.error.addressState'; } if (!ValidationUtils.isValidZipCode(values[INPUT_IDS.ADDRESS.zipCode])) { - errors[INPUT_IDS.ADDRESS.zipCode] = this.props.translate('bankAccount.error.zipCode'); + errors[INPUT_IDS.ADDRESS.zipCode] = 'bankAccount.error.zipCode'; } if (!ValidationUtils.isValidUSPhone(values[INPUT_IDS.PHONE_NUMBER], true)) { - errors[INPUT_IDS.PHONE_NUMBER] = this.props.translate(this.errorTranslationKeys.phoneNumber); + errors[INPUT_IDS.PHONE_NUMBER] = this.errorTranslationKeys.phoneNumber; } // this.props.walletAdditionalDetails stores errors returned by the server. If the server returns an SSN error // then the user needs to provide the full 9 digit SSN. if (this.props.walletAdditionalDetails.errorCode === CONST.WALLET.ERROR.SSN) { if (!ValidationUtils.isValidSSNFullNine(values[INPUT_IDS.SSN])) { - errors[INPUT_IDS.SSN] = this.props.translate(this.errorTranslationKeys.ssnFull9); + errors[INPUT_IDS.SSN] = this.errorTranslationKeys.ssnFull9; } } else if (!ValidationUtils.isValidSSNLastFour(values[INPUT_IDS.SSN])) { - errors[INPUT_IDS.SSN] = this.props.translate(this.errorTranslationKeys.ssn); + errors[INPUT_IDS.SSN] = this.errorTranslationKeys.ssn; } return errors; From f2bc7c591cfcf13fcaac66ed6a14d55363c7d1ab Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 07:30:25 +0100 Subject: [PATCH 015/100] [Refactor] WorkspaceRoom - Return Error keys from Form validation method --- src/pages/settings/Report/RoomNamePage.js | 10 +++++----- src/pages/workspace/WorkspaceNewRoomPage.js | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/pages/settings/Report/RoomNamePage.js b/src/pages/settings/Report/RoomNamePage.js index 89baaca72c79..9bd7f1812e67 100644 --- a/src/pages/settings/Report/RoomNamePage.js +++ b/src/pages/settings/Report/RoomNamePage.js @@ -48,21 +48,21 @@ const RoomNamePage = (props) => { if (!values.roomName || values.roomName === CONST.POLICY.ROOM_PREFIX) { // We error if the user doesn't enter a room name or left blank - ErrorUtils.addErrorMessage(errors, 'roomName', translate('newRoomPage.pleaseEnterRoomName')); + ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.pleaseEnterRoomName'); } else if (!ValidationUtils.isValidRoomName(values.roomName)) { // We error if the room name has invalid characters - ErrorUtils.addErrorMessage(errors, 'roomName', translate('newRoomPage.roomNameInvalidError')); + ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomNameInvalidError'); } else if (ValidationUtils.isReservedRoomName(values.roomName)) { // Certain names are reserved for default rooms and should not be used for policy rooms. - ErrorUtils.addErrorMessage(errors, 'roomName', translate('newRoomPage.roomNameReservedError', {reservedName: values.roomName})); + ErrorUtils.addErrorMessage(errors, 'roomName', ['newRoomPage.roomNameReservedError', {reservedName: values.roomName}]); } else if (ValidationUtils.isExistingRoomName(values.roomName, reports, report.policyID)) { // The room name can't be set to one that already exists on the policy - ErrorUtils.addErrorMessage(errors, 'roomName', translate('newRoomPage.roomAlreadyExistsError')); + ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomAlreadyExistsError'); } return errors; }, - [report, reports, translate], + [report, reports], ); return ( diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index 60583cbc95e8..5a23a093bf14 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -101,16 +101,16 @@ class WorkspaceNewRoomPage extends React.Component { if (!values.roomName || values.roomName === CONST.POLICY.ROOM_PREFIX) { // We error if the user doesn't enter a room name or left blank - ErrorUtils.addErrorMessage(errors, 'roomName', this.props.translate('newRoomPage.pleaseEnterRoomName')); + ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.pleaseEnterRoomName'); } else if (values.roomName !== CONST.POLICY.ROOM_PREFIX && !ValidationUtils.isValidRoomName(values.roomName)) { // We error if the room name has invalid characters - ErrorUtils.addErrorMessage(errors, 'roomName', this.props.translate('newRoomPage.roomNameInvalidError')); + ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomNameInvalidError'); } else if (ValidationUtils.isReservedRoomName(values.roomName)) { // Certain names are reserved for default rooms and should not be used for policy rooms. - ErrorUtils.addErrorMessage(errors, 'roomName', this.props.translate('newRoomPage.roomNameReservedError', {reservedName: values.roomName})); + ErrorUtils.addErrorMessage(errors, 'roomName', ['newRoomPage.roomNameReservedError', {reservedName: values.roomName}]); } else if (ValidationUtils.isExistingRoomName(values.roomName, this.props.reports, values.policyID)) { // Certain names are reserved for default rooms and should not be used for policy rooms. - ErrorUtils.addErrorMessage(errors, 'roomName', this.props.translate('newRoomPage.roomAlreadyExistsError')); + ErrorUtils.addErrorMessage(errors, 'roomName', 'newRoomPage.roomAlreadyExistsError'); } if (!values.policyID) { From 5d9caeba24790d057260222dccc40743b3307c9b Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 07:32:24 +0100 Subject: [PATCH 016/100] Accept array, as some errors has variables parameter --- src/libs/ErrorUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ErrorUtils.js b/src/libs/ErrorUtils.js index 03a26d8fa14c..e4f1b7bff877 100644 --- a/src/libs/ErrorUtils.js +++ b/src/libs/ErrorUtils.js @@ -91,7 +91,7 @@ function getLatestErrorField(onyxData, fieldName) { * Method used to generate error message for given inputID * @param {Object} errors - An object containing current errors in the form * @param {String} inputID - * @param {String} message - Message to assign to the inputID errors + * @param {String|Array} message - Message to assign to the inputID errors * */ function addErrorMessage(errors, inputID, message) { From 5e0ef3a9557e813fa590a86f23506025ad18fd1f Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 07:55:00 +0100 Subject: [PATCH 017/100] [Refactor] TaskTitle - Return Error keys from Form validation methods of different TaskTitle forms --- src/pages/tasks/NewTaskDetailsPage.js | 2 +- src/pages/tasks/NewTaskTitlePage.js | 2 +- src/pages/tasks/TaskTitlePage.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/tasks/NewTaskDetailsPage.js b/src/pages/tasks/NewTaskDetailsPage.js index 383134c434bb..2052fbcc3303 100644 --- a/src/pages/tasks/NewTaskDetailsPage.js +++ b/src/pages/tasks/NewTaskDetailsPage.js @@ -53,7 +53,7 @@ const NewTaskPage = (props) => { if (!values.taskTitle) { // We error if the user doesn't enter a task name - ErrorUtils.addErrorMessage(errors, 'taskTitle', props.translate('newTaskPage.pleaseEnterTaskName')); + ErrorUtils.addErrorMessage(errors, 'taskTitle', 'newTaskPage.pleaseEnterTaskName'); } return errors; diff --git a/src/pages/tasks/NewTaskTitlePage.js b/src/pages/tasks/NewTaskTitlePage.js index 82e5b14a9e3e..6f1b8bdf940c 100644 --- a/src/pages/tasks/NewTaskTitlePage.js +++ b/src/pages/tasks/NewTaskTitlePage.js @@ -48,7 +48,7 @@ const NewTaskTitlePage = (props) => { if (!values.taskTitle) { // We error if the user doesn't enter a task name - ErrorUtils.addErrorMessage(errors, 'taskTitle', props.translate('newTaskPage.pleaseEnterTaskName')); + ErrorUtils.addErrorMessage(errors, 'taskTitle', 'newTaskPage.pleaseEnterTaskName'); } return errors; diff --git a/src/pages/tasks/TaskTitlePage.js b/src/pages/tasks/TaskTitlePage.js index 777b2133ebe6..655c2e59a8f2 100644 --- a/src/pages/tasks/TaskTitlePage.js +++ b/src/pages/tasks/TaskTitlePage.js @@ -48,12 +48,12 @@ function TaskTitlePage(props) { const errors = {}; if (_.isEmpty(values.title)) { - errors.title = props.translate('newTaskPage.pleaseEnterTaskName'); + errors.title = 'newTaskPage.pleaseEnterTaskName'; } return errors; }, - [props], + [], ); const submit = useCallback( From b0d9a39e991bafb9d939050bc60b6dad00f343d6 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 08:17:48 +0100 Subject: [PATCH 018/100] [Refactor] Personal details - Return Error keys from Form validation methods of different Personal details forms --- src/libs/ValidationUtils.js | 9 ++++----- src/pages/settings/Profile/DisplayNamePage.js | 6 +++--- .../Profile/PersonalDetails/DateOfBirthPage.js | 4 ++-- .../settings/Profile/PersonalDetails/LegalNamePage.js | 11 +++++------ 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/libs/ValidationUtils.js b/src/libs/ValidationUtils.js index 7cefd11ec799..4778669840a8 100644 --- a/src/libs/ValidationUtils.js +++ b/src/libs/ValidationUtils.js @@ -5,7 +5,6 @@ import {parsePhoneNumber} from 'awesome-phonenumber'; import CONST from '../CONST'; import * as CardUtils from './CardUtils'; import * as LoginUtils from './LoginUtils'; -import * as Localize from './Localize'; /** * Implements the Luhn Algorithm, a checksum formula used to validate credit card @@ -225,22 +224,22 @@ function meetsMaximumAgeRequirement(date) { * @param {String} date * @param {Number} minimumAge * @param {Number} maximumAge - * @returns {String} + * @returns {String|Array} */ function getAgeRequirementError(date, minimumAge, maximumAge) { const recentDate = moment().startOf('day').subtract(minimumAge, 'years'); const longAgoDate = moment().startOf('day').subtract(maximumAge, 'years'); const testDate = moment(date); if (!testDate.isValid()) { - return Localize.translateLocal('common.error.dateInvalid'); + return 'common.error.dateInvalid'; } if (testDate.isBetween(longAgoDate, recentDate, undefined, '[]')) { return ''; } if (testDate.isSameOrAfter(recentDate)) { - return Localize.translateLocal('privatePersonalDetails.error.dateShouldBeBefore', {dateString: recentDate.format(CONST.DATE.MOMENT_FORMAT_STRING)}); + return ['privatePersonalDetails.error.dateShouldBeBefore', {dateString: recentDate.format(CONST.DATE.MOMENT_FORMAT_STRING)}]; } - return Localize.translateLocal('privatePersonalDetails.error.dateShouldBeAfter', {dateString: longAgoDate.format(CONST.DATE.MOMENT_FORMAT_STRING)}); + return ['privatePersonalDetails.error.dateShouldBeAfter', {dateString: longAgoDate.format(CONST.DATE.MOMENT_FORMAT_STRING)}]; } /** diff --git a/src/pages/settings/Profile/DisplayNamePage.js b/src/pages/settings/Profile/DisplayNamePage.js index 2649db5a1805..927f3358ce90 100644 --- a/src/pages/settings/Profile/DisplayNamePage.js +++ b/src/pages/settings/Profile/DisplayNamePage.js @@ -56,15 +56,15 @@ class DisplayNamePage extends Component { // First we validate the first name field if (!ValidationUtils.isValidDisplayName(values.firstName)) { - ErrorUtils.addErrorMessage(errors, 'firstName', this.props.translate('personalDetails.error.hasInvalidCharacter')); + ErrorUtils.addErrorMessage(errors, 'firstName', 'personalDetails.error.hasInvalidCharacter'); } if (ValidationUtils.doesContainReservedWord(values.firstName, CONST.DISPLAY_NAME.RESERVED_FIRST_NAMES)) { - ErrorUtils.addErrorMessage(errors, 'firstName', this.props.translate('personalDetails.error.containsReservedWord')); + ErrorUtils.addErrorMessage(errors, 'firstName', 'personalDetails.error.containsReservedWord'); } // Then we validate the last name field if (!ValidationUtils.isValidDisplayName(values.lastName)) { - errors.lastName = this.props.translate('personalDetails.error.hasInvalidCharacter'); + errors.lastName = 'personalDetails.error.hasInvalidCharacter'; } return errors; diff --git a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js index cd1ed1ac0895..057bca03e2ac 100644 --- a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js +++ b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js @@ -56,7 +56,7 @@ const DateOfBirthPage = ({translate, route, privatePersonalDetails}) => { const maximumAge = CONST.DATE_BIRTH.MAX_AGE; if (!values.dob || !ValidationUtils.isValidDate(values.dob)) { - errors.dob = translate('common.error.fieldRequired'); + errors.dob = 'common.error.fieldRequired'; } const dateError = ValidationUtils.getAgeRequirementError(values.dob, minimumAge, maximumAge); if (dateError) { @@ -65,7 +65,7 @@ const DateOfBirthPage = ({translate, route, privatePersonalDetails}) => { return errors; }, - [translate], + [], ); return ( diff --git a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js index 41139e74bcb7..438c803e9b7f 100644 --- a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js +++ b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js @@ -44,27 +44,26 @@ const updateLegalName = (values) => { function LegalNamePage(props) { const legalFirstName = lodashGet(props.privatePersonalDetails, 'legalFirstName', ''); const legalLastName = lodashGet(props.privatePersonalDetails, 'legalLastName', ''); - const translate = props.translate; const validate = useCallback( (values) => { const errors = {}; if (!ValidationUtils.isValidLegalName(values.legalFirstName)) { - errors.legalFirstName = translate('privatePersonalDetails.error.hasInvalidCharacter'); + errors.legalFirstName = 'privatePersonalDetails.error.hasInvalidCharacter'; } else if (_.isEmpty(values.legalFirstName)) { - errors.legalFirstName = translate('common.error.fieldRequired'); + errors.legalFirstName = 'common.error.fieldRequired'; } if (!ValidationUtils.isValidLegalName(values.legalLastName)) { - errors.legalLastName = translate('privatePersonalDetails.error.hasInvalidCharacter'); + errors.legalLastName = 'privatePersonalDetails.error.hasInvalidCharacter'; } else if (_.isEmpty(values.legalLastName)) { - errors.legalLastName = translate('common.error.fieldRequired'); + errors.legalLastName = 'common.error.fieldRequired'; } return errors; }, - [translate], + [], ); return ( From 168a8b915363d1a1b984f480f2b4807b760b4e97 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 08:45:36 +0100 Subject: [PATCH 019/100] [Refactor] NewContactMethodPage - Return Error keys from Form validation method --- .../settings/Profile/Contacts/NewContactMethodPage.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/NewContactMethodPage.js b/src/pages/settings/Profile/Contacts/NewContactMethodPage.js index a0ffcb293b8b..af339132d192 100644 --- a/src/pages/settings/Profile/Contacts/NewContactMethodPage.js +++ b/src/pages/settings/Profile/Contacts/NewContactMethodPage.js @@ -82,19 +82,19 @@ function NewContactMethodPage(props) { const errors = {}; if (_.isEmpty(values.phoneOrEmail)) { - ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', props.translate('contacts.genericFailureMessages.contactMethodRequired')); + ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', 'contacts.genericFailureMessages.contactMethodRequired'); } if (!_.isEmpty(values.phoneOrEmail) && !(parsePhoneNumber(phoneLogin).possible || Str.isValidEmail(values.phoneOrEmail))) { - ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', props.translate('contacts.genericFailureMessages.invalidContactMethod')); + ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', 'contacts.genericFailureMessages.invalidContactMethod'); } if (!_.isEmpty(values.phoneOrEmail) && lodashGet(props.loginList, validateIfnumber || values.phoneOrEmail.toLowerCase())) { - ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', props.translate('contacts.genericFailureMessages.enteredMethodIsAlreadySubmited')); + ErrorUtils.addErrorMessage(errors, 'phoneOrEmail', 'contacts.genericFailureMessages.enteredMethodIsAlreadySubmited'); } if (!Permissions.canUsePasswordlessLogins(props.betas) && _.isEmpty(values.password)) { - errors.password = props.translate('contacts.genericFailureMessages.passwordRequired'); + errors.password = 'contacts.genericFailureMessages.passwordRequired'; } return errors; From 3ae79a8188b7ce87aa2acec290881383013ddae9 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 09:05:51 +0100 Subject: [PATCH 020/100] [Refactor] AddressPage - Return Error keys from Form validation method --- .../settings/Profile/PersonalDetails/AddressPage.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/settings/Profile/PersonalDetails/AddressPage.js b/src/pages/settings/Profile/PersonalDetails/AddressPage.js index 60e873125728..17c91cf133a3 100644 --- a/src/pages/settings/Profile/PersonalDetails/AddressPage.js +++ b/src/pages/settings/Profile/PersonalDetails/AddressPage.js @@ -85,7 +85,7 @@ function AddressPage(props) { // Check "State" dropdown is a valid state if selected Country is USA. if (isUSAForm && !COMMON_CONST.STATES[values.state]) { - errors.state = translate('common.error.fieldRequired'); + errors.state = 'common.error.fieldRequired'; } // Add "Field required" errors if any required field is empty @@ -93,7 +93,7 @@ function AddressPage(props) { if (ValidationUtils.isRequiredFulfilled(values[fieldKey])) { return; } - errors[fieldKey] = translate('common.error.fieldRequired'); + errors[fieldKey] = 'common.error.fieldRequired'; }); // If no country is selected, default value is an empty string and there's no related regex data so we default to an empty object @@ -106,18 +106,18 @@ function AddressPage(props) { if (countrySpecificZipRegex) { if (!countrySpecificZipRegex.test(values.zipPostCode.trim())) { if (ValidationUtils.isRequiredFulfilled(values.zipPostCode.trim())) { - errors.zipPostCode = translate('privatePersonalDetails.error.incorrectZipFormat', {zipFormat: countryZipFormat}); + errors.zipPostCode = ['privatePersonalDetails.error.incorrectZipFormat', {zipFormat: countryZipFormat}]; } else { - errors.zipPostCode = translate('common.error.fieldRequired'); + errors.zipPostCode = 'common.error.fieldRequired'; } } } else if (!CONST.GENERIC_ZIP_CODE_REGEX.test(values.zipPostCode.trim())) { - errors.zipPostCode = translate('privatePersonalDetails.error.incorrectZipFormat'); + errors.zipPostCode = 'privatePersonalDetails.error.incorrectZipFormat'; } return errors; }, - [translate, isUSAForm], + [isUSAForm], ); return ( From 55430ad1b076c3a72f529f80bb7ab7da10d7f041 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 09:26:26 +0100 Subject: [PATCH 021/100] [Refactor] Return Error keys from Form validation method --- src/pages/settings/Security/CloseAccountPage.js | 2 +- src/pages/workspace/WorkspaceInviteMessagePage.js | 2 +- src/pages/workspace/reimburse/WorkspaceRateAndUnitPage.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/settings/Security/CloseAccountPage.js b/src/pages/settings/Security/CloseAccountPage.js index 913a30d4d624..3e7e5f81afb1 100644 --- a/src/pages/settings/Security/CloseAccountPage.js +++ b/src/pages/settings/Security/CloseAccountPage.js @@ -78,7 +78,7 @@ class CloseAccountPage extends Component { const errors = {}; if (_.isEmpty(values.phoneOrEmail) || userEmailOrPhone.toLowerCase() !== values.phoneOrEmail.toLowerCase()) { - errors.phoneOrEmail = this.props.translate('closeAccountPage.enterYourDefaultContactMethod'); + errors.phoneOrEmail = 'closeAccountPage.enterYourDefaultContactMethod'; } return errors; } diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.js b/src/pages/workspace/WorkspaceInviteMessagePage.js index bf0bad6710e6..c416358a5822 100644 --- a/src/pages/workspace/WorkspaceInviteMessagePage.js +++ b/src/pages/workspace/WorkspaceInviteMessagePage.js @@ -132,7 +132,7 @@ class WorkspaceInviteMessagePage extends React.Component { validate() { const errorFields = {}; if (_.isEmpty(this.props.invitedMembersDraft)) { - errorFields.welcomeMessage = this.props.translate('workspace.inviteMessage.inviteNoMembersError'); + errorFields.welcomeMessage = 'workspace.inviteMessage.inviteNoMembersError'; } return errorFields; } diff --git a/src/pages/workspace/reimburse/WorkspaceRateAndUnitPage.js b/src/pages/workspace/reimburse/WorkspaceRateAndUnitPage.js index a13385665196..2150beca2441 100644 --- a/src/pages/workspace/reimburse/WorkspaceRateAndUnitPage.js +++ b/src/pages/workspace/reimburse/WorkspaceRateAndUnitPage.js @@ -95,7 +95,7 @@ class WorkspaceRateAndUnitPage extends React.Component { const decimalSeparator = this.props.toLocaleDigit('.'); const rateValueRegex = RegExp(String.raw`^\d{1,8}([${getPermittedDecimalSeparator(decimalSeparator)}]\d{1,3})?$`, 'i'); if (!rateValueRegex.test(values.rate)) { - errors.rate = this.props.translate('workspace.reimburse.invalidRateError'); + errors.rate = 'workspace.reimburse.invalidRateError'; } return errors; } From 073ba43df5ccdc670294686cae77d7045a38be0b Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 09:36:42 +0100 Subject: [PATCH 022/100] [Refactor] PasswordPage - return Error keys from Form validation method --- src/pages/settings/PasswordPage.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pages/settings/PasswordPage.js b/src/pages/settings/PasswordPage.js index f987cabb3c65..ed53d1da2942 100755 --- a/src/pages/settings/PasswordPage.js +++ b/src/pages/settings/PasswordPage.js @@ -78,10 +78,7 @@ class PasswordPage extends Component { * @returns {String} */ getErrorText(field) { - if (this.state.errors[field]) { - return this.props.translate(this.errorKeysMap[field]); - } - return ''; + return this.state.errors[field] ? this.errorKeysMap[field] : ''; } /** @@ -198,7 +195,9 @@ class PasswordPage extends Component { onChangeText={(text) => this.clearErrorAndSetValue('newPassword', text, ['newPasswordSameAsOld'])} onSubmitEditing={this.submit} /> - {shouldShowNewPasswordPrompt && {this.props.translate('passwordPage.newPasswordPrompt')}} + {shouldShowNewPasswordPrompt && + {this.props.translate('passwordPage.newPasswordPrompt')} + } {_.every(this.state.errors, (error) => !error) && !_.isEmpty(this.props.account.errors) && ( Date: Wed, 7 Jun 2023 09:51:52 +0100 Subject: [PATCH 023/100] [Refactor] WorkspaceSettingsPage - return Error keys from Form validation method --- src/pages/workspace/WorkspaceSettingsPage.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/pages/workspace/WorkspaceSettingsPage.js b/src/pages/workspace/WorkspaceSettingsPage.js index 20bccddd9448..c09e849cf9ce 100644 --- a/src/pages/workspace/WorkspaceSettingsPage.js +++ b/src/pages/workspace/WorkspaceSettingsPage.js @@ -44,8 +44,6 @@ const defaultProps = { }; function WorkspaceSettingsPage(props) { - const nameIsRequiredError = props.translate('workspace.editor.nameIsRequiredError'); - const nameIsTooLongError = props.translate('workspace.editor.nameIsTooLongError'); const currencyItems = useMemo(() => { const currencyListKeys = _.keys(props.currencyList); @@ -74,16 +72,16 @@ function WorkspaceSettingsPage(props) { const name = values.name.trim(); if (!name || !name.length) { - errors.name = nameIsRequiredError; + errors.name = 'workspace.editor.nameIsRequiredError'; } else if ([...name].length > CONST.WORKSPACE_NAME_CHARACTER_LIMIT) { // Uses the spread syntax to count the number of Unicode code points instead of the number of UTF-16 // code units. - errors.name = nameIsTooLongError; + errors.name = 'workspace.editor.nameIsTooLongError'; } return errors; }, - [nameIsRequiredError, nameIsTooLongError], + [], ); const policyName = lodashGet(props.policy, 'name', ''); From 5f572610dec79ee5a3d8932e244f7df6de0ef4d9 Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Wed, 7 Jun 2023 21:22:07 +0530 Subject: [PATCH 024/100] revert from destructive props --- .../report/ReportActionItemMessageEdit.js | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index f48c585376e5..cbeae1f6bbf3 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -80,15 +80,15 @@ const cancelButtonID = 'cancelButton'; const emojiButtonID = 'emojiButton'; const messageEditInput = 'messageEditInput'; -function ReportActionItemMessageEdit({action, forwardedRef, draftMessage, index, isKeyboardShown, isSmallScreenWidth, preferredSkinTone, reportID, shouldDisableEmojiPicker, translate}) { +function ReportActionItemMessageEdit(props) { const [draft, setDraft] = useState(() => { - if (draftMessage === action.message[0].html) { + if (props.draftMessage === props.action.message[0].html) { // We only convert the report action message to markdown if the draft message is unchanged. const parser = new ExpensiMark(); - return parser.htmlToMarkdown(draftMessage).trim(); + return parser.htmlToMarkdown(props.draftMessage).trim(); } // We need to decode saved draft message because it's escaped before saving. - return Str.htmlDecode(draftMessage); + return Str.htmlDecode(props.draftMessage); }); const [selection, setSelection] = useState({start: 0, end: 0}); const [isFocused, setIsFocused] = useState(false); @@ -132,9 +132,9 @@ function ReportActionItemMessageEdit({action, forwardedRef, draftMessage, index, const debouncedSaveDraft = useMemo( () => _.debounce((newDraft) => { - Report.saveReportActionDraft(reportID, action.reportActionID, newDraft); + Report.saveReportActionDraft(props.reportID, props.action.reportActionID, newDraft); }, 1000), - [reportID, action.reportActionID], + [props.reportID, props.action.reportActionID], ); /** @@ -144,7 +144,7 @@ function ReportActionItemMessageEdit({action, forwardedRef, draftMessage, index, */ const updateDraft = useCallback( (newDraftValue) => { - const {text: newDraft = '', emojis = []} = EmojiUtils.replaceEmojis(newDraftValue, isSmallScreenWidth, preferredSkinTone); + const {text: newDraft = '', emojis = []} = EmojiUtils.replaceEmojis(newDraftValue, props.isSmallScreenWidth, props.preferredSkinTone); if (!_.isEmpty(emojis)) { User.updateFrequentlyUsedEmojis(EmojiUtils.getFrequentlyUsedEmojis(emojis)); @@ -166,10 +166,10 @@ function ReportActionItemMessageEdit({action, forwardedRef, draftMessage, index, // We want to escape the draft message to differentiate the HTML from the report action and the HTML the user drafted. debouncedSaveDraft(_.escape(newDraft)); } else { - debouncedSaveDraft(action.message[0].html); + debouncedSaveDraft(props.action.message[0].html); } }, - [action.message, draft, debouncedSaveDraft, isSmallScreenWidth, preferredSkinTone], + [props.action.message, draft, debouncedSaveDraft, props.isSmallScreenWidth, props.preferredSkinTone], ); /** @@ -177,18 +177,18 @@ function ReportActionItemMessageEdit({action, forwardedRef, draftMessage, index, */ const deleteDraft = useCallback(() => { debouncedSaveDraft.cancel(); - Report.saveReportActionDraft(reportID, action.reportActionID, ''); + Report.saveReportActionDraft(props.reportID, props.action.reportActionID, ''); ComposerActions.setShouldShowComposeInput(true); ReportActionComposeFocusManager.focus(); // Scroll to the last comment after editing to make sure the whole comment is clearly visible in the report. - if (index === 0) { + if (props.index === 0) { const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => { - ReportScrollManager.scrollToIndex({animated: true, index}, false); + ReportScrollManager.scrollToIndex({animated: true, index: props.index}, false); keyboardDidHideListener.remove(); }); } - }, [action.reportActionID, debouncedSaveDraft, index, reportID]); + }, [props.action.reportActionID, debouncedSaveDraft, props.index, props.reportID]); /** * Save the draft of the comment to be the new comment message. This will take the comment out of "edit mode" with @@ -208,12 +208,12 @@ function ReportActionItemMessageEdit({action, forwardedRef, draftMessage, index, // When user tries to save the empty message, it will delete it. Prompt the user to confirm deleting. if (!trimmedNewDraft) { - ReportActionContextMenu.showDeleteModal(reportID, action, false, deleteDraft, () => InteractionManager.runAfterInteractions(() => textInputRef.current.focus())); + ReportActionContextMenu.showDeleteModal(props.reportID, props.action, false, deleteDraft, () => InteractionManager.runAfterInteractions(() => textInputRef.current.focus())); return; } - Report.editReportComment(reportID, action, trimmedNewDraft); + Report.editReportComment(props.reportID, props.action, trimmedNewDraft); deleteDraft(); - }, [action, debouncedSaveDraft, deleteDraft, draft, reportID]); + }, [props.action, debouncedSaveDraft, deleteDraft, draft, props.reportID]); /** * @param {String} emoji @@ -236,7 +236,7 @@ function ReportActionItemMessageEdit({action, forwardedRef, draftMessage, index, */ const triggerSaveOrCancel = useCallback( (e) => { - if (!e || ComposerUtils.canSkipTriggerHotkeys(isSmallScreenWidth, isKeyboardShown)) { + if (!e || ComposerUtils.canSkipTriggerHotkeys(props.isSmallScreenWidth, props.isKeyboardShown)) { return; } if (e.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey && !e.shiftKey) { @@ -247,14 +247,14 @@ function ReportActionItemMessageEdit({action, forwardedRef, draftMessage, index, deleteDraft(); } }, - [deleteDraft, isKeyboardShown, isSmallScreenWidth, publishDraft], + [deleteDraft, props.isKeyboardShown, props.isSmallScreenWidth, publishDraft], ); return ( <> - + [styles.chatItemSubmitButton, StyleUtils.getButtonBackgroundColorStyle(getButtonState(hovered, pressed))]} nativeID={cancelButtonID} @@ -290,17 +290,17 @@ function ReportActionItemMessageEdit({action, forwardedRef, draftMessage, index, ref={(el) => { textInputRef.current = el; // eslint-disable-next-line no-param-reassign - forwardedRef.current = el; + props.forwardedRef.current = el; }} nativeID={messageEditInput} onChangeText={updateDraft} // Debounced saveDraftComment onKeyPress={triggerSaveOrCancel} value={draft} - maxLines={isSmallScreenWidth ? CONST.COMPOSER.MAX_LINES_SMALL_SCREEN : CONST.COMPOSER.MAX_LINES} // This is the same that slack has + maxLines={props.isSmallScreenWidth ? CONST.COMPOSER.MAX_LINES_SMALL_SCREEN : CONST.COMPOSER.MAX_LINES} // This is the same that slack has style={[styles.textInputCompose, styles.flex1, styles.bgTransparent]} onFocus={() => { setIsFocused(true); - ReportScrollManager.scrollToIndex({animated: true, index}, true); + ReportScrollManager.scrollToIndex({animated: true, index: props.index}, true); ComposerActions.setShouldShowComposeInput(false); }} onBlur={(event) => { @@ -323,7 +323,7 @@ function ReportActionItemMessageEdit({action, forwardedRef, draftMessage, index, InteractionManager.runAfterInteractions(() => textInputRef.current.focus())} onEmojiSelected={addEmojiToTextBox} nativeID={emojiButtonID} @@ -331,7 +331,7 @@ function ReportActionItemMessageEdit({action, forwardedRef, draftMessage, index, - + Date: Wed, 7 Jun 2023 21:26:06 +0530 Subject: [PATCH 025/100] function cleanup --- .../report/ReportActionItemMessageEdit.js | 58 +++++++++---------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index cbeae1f6bbf3..63f222835e02 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -107,10 +107,8 @@ function ReportActionItemMessageEdit(props) { }); return prevDraft; }); - }, []); - useEffect( - () => () => { + return () => { // Skip if this is not the focused message so the other edit composer stays focused. if (!isFocused) { return; @@ -119,10 +117,9 @@ function ReportActionItemMessageEdit(props) { // Show the main composer when the focused message is deleted from another client // to prevent the main composer stays hidden until we swtich to another chat. ComposerActions.setShouldShowComposeInput(true); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps -- for willUnmount lifecycle - [], - ); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps -- we need it to call it once on mount + }, []); /** * Save the draft of the comment. This debounced so that we're not ceaselessly saving your edit. Saving the draft @@ -140,25 +137,27 @@ function ReportActionItemMessageEdit(props) { /** * Update the value of the draft in Onyx * - * @param {String} newDraftValue + * @param {String} newDraftInput */ const updateDraft = useCallback( - (newDraftValue) => { - const {text: newDraft = '', emojis = []} = EmojiUtils.replaceEmojis(newDraftValue, props.isSmallScreenWidth, props.preferredSkinTone); + (newDraftInput) => { + const {text: newDraft = '', emojis = []} = EmojiUtils.replaceEmojis(newDraftInput, props.isSmallScreenWidth, props.preferredSkinTone); if (!_.isEmpty(emojis)) { User.updateFrequentlyUsedEmojis(EmojiUtils.getFrequentlyUsedEmojis(emojis)); } - if (newDraftValue !== newDraft) { - setSelection((prevSelection) => { - const remainder = draft.slice(prevSelection.end).length; - return { - start: newDraft.length - remainder, - end: newDraft.length - remainder, - }; - }); - } - setDraft(newDraft); + setDraft((prevDraft) => { + if (newDraftInput !== newDraft) { + setSelection((prevSelection) => { + const remainder = prevDraft.slice(prevSelection.end).length; + return { + start: newDraft.length - remainder, + end: newDraft.length - remainder, + }; + }); + } + return newDraft; + }); // This component is rendered only when draft is set to a non-empty string. In order to prevent component // unmount when user deletes content of textarea, we set previous message instead of empty string. @@ -169,7 +168,7 @@ function ReportActionItemMessageEdit(props) { debouncedSaveDraft(props.action.message[0].html); } }, - [props.action.message, draft, debouncedSaveDraft, props.isSmallScreenWidth, props.preferredSkinTone], + [props.action.message, debouncedSaveDraft, props.isSmallScreenWidth, props.preferredSkinTone], ); /** @@ -218,16 +217,13 @@ function ReportActionItemMessageEdit(props) { /** * @param {String} emoji */ - const addEmojiToTextBox = useCallback( - (emoji) => { - setSelection((prevSelection) => ({ - start: prevSelection.start + emoji.length, - end: prevSelection.start + emoji.length, - })); - updateDraft(ComposerUtils.insertText(draft, selection, emoji)); - }, - [draft, selection, updateDraft], - ); + const addEmojiToTextBox = (emoji) => { + setSelection((prevSelection) => ({ + start: prevSelection.start + emoji.length, + end: prevSelection.start + emoji.length, + })); + updateDraft(ComposerUtils.insertText(draft, selection, emoji)); + }; /** * Key event handlers that short cut to saving/canceling. From 1d59b7e1a708344688ca50c6e622e5423003792c Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 21:11:50 +0100 Subject: [PATCH 026/100] [Refactor] DebitCardPage - return Error keys from Form validation method --- .../settings/Payments/AddDebitCardPage.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/pages/settings/Payments/AddDebitCardPage.js b/src/pages/settings/Payments/AddDebitCardPage.js index 7c174c58dbc2..77b7089fd2ef 100644 --- a/src/pages/settings/Payments/AddDebitCardPage.js +++ b/src/pages/settings/Payments/AddDebitCardPage.js @@ -74,39 +74,39 @@ class DebitCardPage extends Component { const errors = {}; if (!values.nameOnCard || !ValidationUtils.isValidCardName(values.nameOnCard)) { - errors.nameOnCard = this.props.translate('addDebitCardPage.error.invalidName'); + errors.nameOnCard = 'addDebitCardPage.error.invalidName'; } if (!values.cardNumber || !ValidationUtils.isValidDebitCard(values.cardNumber.replace(/ /g, ''))) { - errors.cardNumber = this.props.translate('addDebitCardPage.error.debitCardNumber'); + errors.cardNumber = 'addDebitCardPage.error.debitCardNumber'; } if (!values.expirationDate || !ValidationUtils.isValidExpirationDate(values.expirationDate)) { - errors.expirationDate = this.props.translate('addDebitCardPage.error.expirationDate'); + errors.expirationDate = 'addDebitCardPage.error.expirationDate'; } if (!values.securityCode || !ValidationUtils.isValidSecurityCode(values.securityCode)) { - errors.securityCode = this.props.translate('addDebitCardPage.error.securityCode'); + errors.securityCode = 'addDebitCardPage.error.securityCode'; } if (!values.addressStreet || !ValidationUtils.isValidAddress(values.addressStreet)) { - errors.addressStreet = this.props.translate('addDebitCardPage.error.addressStreet'); + errors.addressStreet = 'addDebitCardPage.error.addressStreet'; } if (!values.addressZipCode || !ValidationUtils.isValidZipCode(values.addressZipCode)) { - errors.addressZipCode = this.props.translate('addDebitCardPage.error.addressZipCode'); + errors.addressZipCode = 'addDebitCardPage.error.addressZipCode'; } if (!values.addressState || !values.addressState) { - errors.addressState = this.props.translate('addDebitCardPage.error.addressState'); + errors.addressState = 'addDebitCardPage.error.addressState'; } if (!Permissions.canUsePasswordlessLogins(this.props.betas) && (!values.password || _.isEmpty(values.password.trim()))) { - errors.password = this.props.translate('addDebitCardPage.error.password'); + errors.password = 'addDebitCardPage.error.password'; } if (!values.acceptTerms) { - errors.acceptTerms = this.props.translate('common.error.acceptTerms'); + errors.acceptTerms = 'common.error.acceptTerms'; } return errors; From 39677ddc034cb873b569461f453f295a8197c57b Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 21:16:36 +0100 Subject: [PATCH 027/100] [Refactor] ACHContractStep - return Error keys from Form validation method --- .../ReimbursementAccount/ACHContractStep.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pages/ReimbursementAccount/ACHContractStep.js b/src/pages/ReimbursementAccount/ACHContractStep.js index ae1225291473..df922173a7af 100644 --- a/src/pages/ReimbursementAccount/ACHContractStep.js +++ b/src/pages/ReimbursementAccount/ACHContractStep.js @@ -60,38 +60,38 @@ class ACHContractStep extends React.Component { _.each(requiredFields, (inputKey) => { if (!ValidationUtils.isRequiredFulfilled(values[`beneficialOwner_${ownerKey}_${inputKey}`])) { const errorKey = errorKeys[inputKey] || inputKey; - errors[`beneficialOwner_${ownerKey}_${inputKey}`] = this.props.translate(`bankAccount.error.${errorKey}`); + errors[`beneficialOwner_${ownerKey}_${inputKey}`] = `bankAccount.error.${errorKey}`; } }); if (values[`beneficialOwner_${ownerKey}_dob`]) { if (!ValidationUtils.meetsMinimumAgeRequirement(values[`beneficialOwner_${ownerKey}_dob`])) { - errors[`beneficialOwner_${ownerKey}_dob`] = this.props.translate('bankAccount.error.age'); + errors[`beneficialOwner_${ownerKey}_dob`] = 'bankAccount.error.age'; } else if (!ValidationUtils.meetsMaximumAgeRequirement(values[`beneficialOwner_${ownerKey}_dob`])) { - errors[`beneficialOwner_${ownerKey}_dob`] = this.props.translate('bankAccount.error.dob'); + errors[`beneficialOwner_${ownerKey}_dob`] = 'bankAccount.error.dob'; } } if (values[`beneficialOwner_${ownerKey}_ssnLast4`] && !ValidationUtils.isValidSSNLastFour(values[`beneficialOwner_${ownerKey}_ssnLast4`])) { - errors[`beneficialOwner_${ownerKey}_ssnLast4`] = this.props.translate('bankAccount.error.ssnLast4'); + errors[`beneficialOwner_${ownerKey}_ssnLast4`] = 'bankAccount.error.ssnLast4'; } if (values[`beneficialOwner_${ownerKey}_street`] && !ValidationUtils.isValidAddress(values[`beneficialOwner_${ownerKey}_street`])) { - errors[`beneficialOwner_${ownerKey}_street`] = this.props.translate('bankAccount.error.addressStreet'); + errors[`beneficialOwner_${ownerKey}_street`] = 'bankAccount.error.addressStreet'; } if (values[`beneficialOwner_${ownerKey}_zipCode`] && !ValidationUtils.isValidZipCode(values[`beneficialOwner_${ownerKey}_zipCode`])) { - errors[`beneficialOwner_${ownerKey}_zipCode`] = this.props.translate('bankAccount.error.zipCode'); + errors[`beneficialOwner_${ownerKey}_zipCode`] = 'bankAccount.error.zipCode'; } }); } if (!ValidationUtils.isRequiredFulfilled(values.acceptTermsAndConditions)) { - errors.acceptTermsAndConditions = this.props.translate('common.error.acceptTerms'); + errors.acceptTermsAndConditions = 'common.error.acceptTerms'; } if (!ValidationUtils.isRequiredFulfilled(values.certifyTrueInformation)) { - errors.certifyTrueInformation = this.props.translate('beneficialOwnersStep.error.certify'); + errors.certifyTrueInformation = 'beneficialOwnersStep.error.certify'; } return errors; From 882ab3cda7c8822460d68d8c42b702f633db85ce Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 21:17:38 +0100 Subject: [PATCH 028/100] [Refactor] BankAccountManualStep - return Error keys from Form validation method --- src/pages/ReimbursementAccount/BankAccountManualStep.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/ReimbursementAccount/BankAccountManualStep.js b/src/pages/ReimbursementAccount/BankAccountManualStep.js index f8eeb6628495..5e8f46be00e5 100644 --- a/src/pages/ReimbursementAccount/BankAccountManualStep.js +++ b/src/pages/ReimbursementAccount/BankAccountManualStep.js @@ -41,13 +41,13 @@ class BankAccountManualStep extends React.Component { !values.accountNumber || (!CONST.BANK_ACCOUNT.REGEX.US_ACCOUNT_NUMBER.test(values.accountNumber.trim()) && !CONST.BANK_ACCOUNT.REGEX.MASKED_US_ACCOUNT_NUMBER.test(values.accountNumber.trim())) ) { - errorFields.accountNumber = this.props.translate('bankAccount.error.accountNumber'); + errorFields.accountNumber = 'bankAccount.error.accountNumber'; } if (!routingNumber || !CONST.BANK_ACCOUNT.REGEX.SWIFT_BIC.test(routingNumber) || !ValidationUtils.isValidRoutingNumber(routingNumber)) { - errorFields.routingNumber = this.props.translate('bankAccount.error.routingNumber'); + errorFields.routingNumber = 'bankAccount.error.routingNumber'; } if (!values.acceptTerms) { - errorFields.acceptTerms = this.props.translate('common.error.acceptTerms'); + errorFields.acceptTerms = 'common.error.acceptTerms'; } return errorFields; From 18575e498551ae5431381c0cf61b3f98ddf45eab Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 21:20:09 +0100 Subject: [PATCH 029/100] [Refactor] CompanyStep - return Error keys from Form validation method --- src/pages/ReimbursementAccount/CompanyStep.js | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js index 1265469abd26..e44d0562b58e 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -83,53 +83,53 @@ class CompanyStep extends React.Component { const errors = {}; if (!values.companyName) { - errors.companyName = this.props.translate('bankAccount.error.companyName'); + errors.companyName = 'bankAccount.error.companyName'; } if (!values.addressStreet || !ValidationUtils.isValidAddress(values.addressStreet)) { - errors.addressStreet = this.props.translate('bankAccount.error.addressStreet'); + errors.addressStreet = 'bankAccount.error.addressStreet'; } if (!values.addressZipCode || !ValidationUtils.isValidZipCode(values.addressZipCode)) { - errors.addressZipCode = this.props.translate('bankAccount.error.zipCode'); + errors.addressZipCode = 'bankAccount.error.zipCode'; } if (!values.addressCity) { - errors.addressCity = this.props.translate('bankAccount.error.addressCity'); + errors.addressCity = 'bankAccount.error.addressCity'; } if (!values.addressState) { - errors.addressState = this.props.translate('bankAccount.error.addressState'); + errors.addressState = 'bankAccount.error.addressState'; } if (!values.companyPhone || !ValidationUtils.isValidUSPhone(values.companyPhone, true)) { - errors.companyPhone = this.props.translate('bankAccount.error.phoneNumber'); + errors.companyPhone = 'bankAccount.error.phoneNumber'; } if (!values.website || !ValidationUtils.isValidWebsite(values.website)) { - errors.website = this.props.translate('bankAccount.error.website'); + errors.website = 'bankAccount.error.website'; } if (!values.companyTaxID || !ValidationUtils.isValidTaxID(values.companyTaxID)) { - errors.companyTaxID = this.props.translate('bankAccount.error.taxID'); + errors.companyTaxID = 'bankAccount.error.taxID'; } if (!values.incorporationType) { - errors.incorporationType = this.props.translate('bankAccount.error.companyType'); + errors.incorporationType = 'bankAccount.error.companyType'; } if (!values.incorporationDate || !ValidationUtils.isValidDate(values.incorporationDate)) { - errors.incorporationDate = this.props.translate('common.error.dateInvalid'); + errors.incorporationDate = 'common.error.dateInvalid'; } else if (!values.incorporationDate || !ValidationUtils.isValidPastDate(values.incorporationDate)) { - errors.incorporationDate = this.props.translate('bankAccount.error.incorporationDateFuture'); + errors.incorporationDate = 'bankAccount.error.incorporationDateFuture'; } if (!values.incorporationState) { - errors.incorporationState = this.props.translate('bankAccount.error.incorporationState'); + errors.incorporationState = 'bankAccount.error.incorporationState'; } if (!values.hasNoConnectionToCannabis) { - errors.hasNoConnectionToCannabis = this.props.translate('bankAccount.error.restrictedBusiness'); + errors.hasNoConnectionToCannabis = 'bankAccount.error.restrictedBusiness'; } return errors; From 370eca3dd764117faaa3a7eebb75600089f3224a Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 21:22:26 +0100 Subject: [PATCH 030/100] [Refactor] RequesterStep - return Error keys from Form validation method --- .../ReimbursementAccount/RequestorStep.js | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index b69067550848..c6496db73adc 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -41,51 +41,51 @@ class RequestorStep extends React.Component { const errors = {}; if (!ValidationUtils.isRequiredFulfilled(values.firstName)) { - errors.firstName = this.props.translate('bankAccount.error.firstName'); + errors.firstName = 'bankAccount.error.firstName'; } if (!ValidationUtils.isRequiredFulfilled(values.lastName)) { - errors.lastName = this.props.translate('bankAccount.error.lastName'); + errors.lastName = 'bankAccount.error.lastName'; } if (!ValidationUtils.isRequiredFulfilled(values.dob)) { - errors.dob = this.props.translate('bankAccount.error.dob'); + errors.dob = 'bankAccount.error.dob'; } if (values.dob) { if (!ValidationUtils.meetsMinimumAgeRequirement(values.dob)) { - errors.dob = this.props.translate('bankAccount.error.age'); + errors.dob = 'bankAccount.error.age'; } else if (!ValidationUtils.meetsMaximumAgeRequirement(values.dob)) { - errors.dob = this.props.translate('bankAccount.error.dob'); + errors.dob = 'bankAccount.error.dob'; } } if (!ValidationUtils.isRequiredFulfilled(values.ssnLast4) || !ValidationUtils.isValidSSNLastFour(values.ssnLast4)) { - errors.ssnLast4 = this.props.translate('bankAccount.error.ssnLast4'); + errors.ssnLast4 = 'bankAccount.error.ssnLast4'; } if (!ValidationUtils.isRequiredFulfilled(values.requestorAddressStreet)) { - errors.requestorAddressStreet = this.props.translate('bankAccount.error.address'); + errors.requestorAddressStreet = 'bankAccount.error.address'; } if (values.requestorAddressStreet && !ValidationUtils.isValidAddress(values.requestorAddressStreet)) { - errors.requestorAddressStreet = this.props.translate('bankAccount.error.addressStreet'); + errors.requestorAddressStreet = 'bankAccount.error.addressStreet'; } if (!ValidationUtils.isRequiredFulfilled(values.requestorAddressCity)) { - errors.requestorAddressCity = this.props.translate('bankAccount.error.addressCity'); + errors.requestorAddressCity = 'bankAccount.error.addressCity'; } if (!ValidationUtils.isRequiredFulfilled(values.requestorAddressState)) { - errors.requestorAddressState = this.props.translate('bankAccount.error.addressState'); + errors.requestorAddressState = 'bankAccount.error.addressState'; } if (!ValidationUtils.isRequiredFulfilled(values.requestorAddressZipCode) || !ValidationUtils.isValidZipCode(values.requestorAddressZipCode)) { - errors.requestorAddressZipCode = this.props.translate('bankAccount.error.zipCode'); + errors.requestorAddressZipCode = 'bankAccount.error.zipCode'; } if (!ValidationUtils.isRequiredFulfilled(values.isControllingOfficer)) { - errors.isControllingOfficer = this.props.translate('requestorStep.isControllingOfficerError'); + errors.isControllingOfficer = 'requestorStep.isControllingOfficerError'; } return errors; From 589746792ce348d608b9fcb7cc58a306511ca731 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 21:23:23 +0100 Subject: [PATCH 031/100] [Refactor] ValidationStep - return Error keys from Form validation method --- src/pages/ReimbursementAccount/ValidationStep.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/ValidationStep.js b/src/pages/ReimbursementAccount/ValidationStep.js index e8dfeae77be7..d07f23d50843 100644 --- a/src/pages/ReimbursementAccount/ValidationStep.js +++ b/src/pages/ReimbursementAccount/ValidationStep.js @@ -71,7 +71,7 @@ class ValidationStep extends React.Component { if (ValidationUtils.isRequiredFulfilled(filteredValue)) { return; } - errors[key] = this.props.translate('common.error.invalidAmount'); + errors[key] = 'common.error.invalidAmount'; }); return errors; From d8d4d684671cb00698048fb629c984b3b9968fd2 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 21:57:28 +0100 Subject: [PATCH 032/100] [Refactor] WorkspaceMembersPage - return Error keys from Form validation method --- src/pages/workspace/WorkspaceMembersPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index 5206c34c1a49..ac5c93226733 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -291,7 +291,7 @@ class WorkspaceMembersPage extends React.Component { return; } - errors[member] = this.props.translate('workspace.people.error.cannotRemove'); + errors[member] = 'workspace.people.error.cannotRemove'; }); this.setState({errors}); From 47109f719d4443c4483b580fe924ac365dba0b68 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 22:01:46 +0100 Subject: [PATCH 033/100] [Refactor] BankAccountPlaidStep - return Error keys from Form validation method --- src/pages/ReimbursementAccount/BankAccountPlaidStep.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/BankAccountPlaidStep.js b/src/pages/ReimbursementAccount/BankAccountPlaidStep.js index 3af673084976..707828436d91 100644 --- a/src/pages/ReimbursementAccount/BankAccountPlaidStep.js +++ b/src/pages/ReimbursementAccount/BankAccountPlaidStep.js @@ -49,7 +49,7 @@ class BankAccountPlaidStep extends React.Component { validate(values) { const errorFields = {}; if (!values.acceptTerms) { - errorFields.acceptTerms = this.props.translate('common.error.acceptTerms'); + errorFields.acceptTerms = 'common.error.acceptTerms'; } return errorFields; From 48ea9fd08b55ec0346395002d78a43817544091a Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Wed, 7 Jun 2023 22:04:19 +0100 Subject: [PATCH 034/100] Run prettier --- src/pages/settings/PasswordPage.js | 4 +-- .../PersonalDetails/DateOfBirthPage.js | 29 ++++++++--------- .../Profile/PersonalDetails/LegalNamePage.js | 31 +++++++++---------- src/pages/tasks/TaskTitlePage.js | 17 +++++----- src/pages/workspace/WorkspaceSettingsPage.js | 28 +++++++---------- 5 files changed, 47 insertions(+), 62 deletions(-) diff --git a/src/pages/settings/PasswordPage.js b/src/pages/settings/PasswordPage.js index ed53d1da2942..ab352851c76b 100755 --- a/src/pages/settings/PasswordPage.js +++ b/src/pages/settings/PasswordPage.js @@ -195,9 +195,7 @@ class PasswordPage extends Component { onChangeText={(text) => this.clearErrorAndSetValue('newPassword', text, ['newPasswordSameAsOld'])} onSubmitEditing={this.submit} /> - {shouldShowNewPasswordPrompt && - {this.props.translate('passwordPage.newPasswordPrompt')} - } + {shouldShowNewPasswordPrompt && {this.props.translate('passwordPage.newPasswordPrompt')}} {_.every(this.state.errors, (error) => !error) && !_.isEmpty(this.props.account.errors) && ( { * @param {String} values.dob - date of birth * @returns {Object} - An object containing the errors for each inputID */ - const validate = useCallback( - (values) => { - const errors = {}; - const minimumAge = CONST.DATE_BIRTH.MIN_AGE; - const maximumAge = CONST.DATE_BIRTH.MAX_AGE; + const validate = useCallback((values) => { + const errors = {}; + const minimumAge = CONST.DATE_BIRTH.MIN_AGE; + const maximumAge = CONST.DATE_BIRTH.MAX_AGE; - if (!values.dob || !ValidationUtils.isValidDate(values.dob)) { - errors.dob = 'common.error.fieldRequired'; - } - const dateError = ValidationUtils.getAgeRequirementError(values.dob, minimumAge, maximumAge); - if (dateError) { - errors.dob = dateError; - } + if (!values.dob || !ValidationUtils.isValidDate(values.dob)) { + errors.dob = 'common.error.fieldRequired'; + } + const dateError = ValidationUtils.getAgeRequirementError(values.dob, minimumAge, maximumAge); + if (dateError) { + errors.dob = dateError; + } - return errors; - }, - [], - ); + return errors; + }, []); return ( diff --git a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js index 438c803e9b7f..d743aa0cd983 100644 --- a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js +++ b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js @@ -45,26 +45,23 @@ function LegalNamePage(props) { const legalFirstName = lodashGet(props.privatePersonalDetails, 'legalFirstName', ''); const legalLastName = lodashGet(props.privatePersonalDetails, 'legalLastName', ''); - const validate = useCallback( - (values) => { - const errors = {}; + const validate = useCallback((values) => { + const errors = {}; - if (!ValidationUtils.isValidLegalName(values.legalFirstName)) { - errors.legalFirstName = 'privatePersonalDetails.error.hasInvalidCharacter'; - } else if (_.isEmpty(values.legalFirstName)) { - errors.legalFirstName = 'common.error.fieldRequired'; - } + if (!ValidationUtils.isValidLegalName(values.legalFirstName)) { + errors.legalFirstName = 'privatePersonalDetails.error.hasInvalidCharacter'; + } else if (_.isEmpty(values.legalFirstName)) { + errors.legalFirstName = 'common.error.fieldRequired'; + } - if (!ValidationUtils.isValidLegalName(values.legalLastName)) { - errors.legalLastName = 'privatePersonalDetails.error.hasInvalidCharacter'; - } else if (_.isEmpty(values.legalLastName)) { - errors.legalLastName = 'common.error.fieldRequired'; - } + if (!ValidationUtils.isValidLegalName(values.legalLastName)) { + errors.legalLastName = 'privatePersonalDetails.error.hasInvalidCharacter'; + } else if (_.isEmpty(values.legalLastName)) { + errors.legalLastName = 'common.error.fieldRequired'; + } - return errors; - }, - [], - ); + return errors; + }, []); return ( diff --git a/src/pages/tasks/TaskTitlePage.js b/src/pages/tasks/TaskTitlePage.js index 655c2e59a8f2..0e38fdb81ef4 100644 --- a/src/pages/tasks/TaskTitlePage.js +++ b/src/pages/tasks/TaskTitlePage.js @@ -43,18 +43,15 @@ function TaskTitlePage(props) { * @param {String} values.title * @returns {Object} - An object containing the errors for each inputID */ - const validate = useCallback( - (values) => { - const errors = {}; + const validate = useCallback((values) => { + const errors = {}; - if (_.isEmpty(values.title)) { - errors.title = 'newTaskPage.pleaseEnterTaskName'; - } + if (_.isEmpty(values.title)) { + errors.title = 'newTaskPage.pleaseEnterTaskName'; + } - return errors; - }, - [], - ); + return errors; + }, []); const submit = useCallback( (values) => { diff --git a/src/pages/workspace/WorkspaceSettingsPage.js b/src/pages/workspace/WorkspaceSettingsPage.js index c09e849cf9ce..a94c8a5e9b93 100644 --- a/src/pages/workspace/WorkspaceSettingsPage.js +++ b/src/pages/workspace/WorkspaceSettingsPage.js @@ -44,7 +44,6 @@ const defaultProps = { }; function WorkspaceSettingsPage(props) { - const currencyItems = useMemo(() => { const currencyListKeys = _.keys(props.currencyList); return _.map(currencyListKeys, (currencyCode) => ({ @@ -66,23 +65,20 @@ function WorkspaceSettingsPage(props) { [props.policy.id, props.policy.isPolicyUpdating], ); - const validate = useCallback( - (values) => { - const errors = {}; - const name = values.name.trim(); + const validate = useCallback((values) => { + const errors = {}; + const name = values.name.trim(); - if (!name || !name.length) { - errors.name = 'workspace.editor.nameIsRequiredError'; - } else if ([...name].length > CONST.WORKSPACE_NAME_CHARACTER_LIMIT) { - // Uses the spread syntax to count the number of Unicode code points instead of the number of UTF-16 - // code units. - errors.name = 'workspace.editor.nameIsTooLongError'; - } + if (!name || !name.length) { + errors.name = 'workspace.editor.nameIsRequiredError'; + } else if ([...name].length > CONST.WORKSPACE_NAME_CHARACTER_LIMIT) { + // Uses the spread syntax to count the number of Unicode code points instead of the number of UTF-16 + // code units. + errors.name = 'workspace.editor.nameIsTooLongError'; + } - return errors; - }, - [], - ); + return errors; + }, []); const policyName = lodashGet(props.policy, 'name', ''); From 53a30bf334ae21efe2c1eed67a0c6330555e26ec Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 8 Jun 2023 05:50:33 +0100 Subject: [PATCH 035/100] Accept array, as error can have parameter variables --- src/components/RoomNameInput/roomNameInputPropTypes.js | 2 +- src/components/TextInput/baseTextInputPropTypes.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/RoomNameInput/roomNameInputPropTypes.js b/src/components/RoomNameInput/roomNameInputPropTypes.js index 2f4af1ae2e92..453a986fdd1f 100644 --- a/src/components/RoomNameInput/roomNameInputPropTypes.js +++ b/src/components/RoomNameInput/roomNameInputPropTypes.js @@ -12,7 +12,7 @@ const propTypes = { disabled: PropTypes.bool, /** Error text to show */ - errorText: PropTypes.string, + errorText: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), ...withLocalizePropTypes, diff --git a/src/components/TextInput/baseTextInputPropTypes.js b/src/components/TextInput/baseTextInputPropTypes.js index 45720ceb8c47..fb88d689be86 100644 --- a/src/components/TextInput/baseTextInputPropTypes.js +++ b/src/components/TextInput/baseTextInputPropTypes.js @@ -17,7 +17,7 @@ const propTypes = { placeholder: PropTypes.string, /** Error text to display */ - errorText: PropTypes.string, + errorText: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), /** Icon to display in right side of text input */ icon: PropTypes.func, From d13c04f0fc483f52be6fad23983265893589d3ac Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Thu, 8 Jun 2023 10:28:10 +0530 Subject: [PATCH 036/100] use textInput ref isFocused method instead of isFocused --- src/pages/home/report/ReportActionItemMessageEdit.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index 63f222835e02..58345a885bc7 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -109,8 +109,8 @@ function ReportActionItemMessageEdit(props) { }); return () => { - // Skip if this is not the focused message so the other edit composer stays focused. - if (!isFocused) { + // Skip if this is not the focused message so the other edit composer stays focused + if (!textInputRef.current.isFocused()) { return; } From 7c3d891efa2a0a9757ea9269900c44ceb3697833 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 8 Jun 2023 07:05:39 +0100 Subject: [PATCH 037/100] Remove translation from Form's validate method --- contributingGuides/FORMS.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contributingGuides/FORMS.md b/contributingGuides/FORMS.md index b8aac1e38baa..01f145dafbc6 100644 --- a/contributingGuides/FORMS.md +++ b/contributingGuides/FORMS.md @@ -114,10 +114,10 @@ Here's an example for a form that has two inputs, `routingNumber` and `accountNu function validate(values) { const errors = {}; if (!values.routingNumber) { - errors.routingNumber = props.translate(CONST.ERRORS.ROUTING_NUMBER); + errors.routingNumber = CONST.ERRORS.ROUTING_NUMBER; } if (!values.accountNumber) { - errors.accountNumber = props.translate(CONST.ERRORS.ACCOUNT_NUMBER); + errors.accountNumber = CONST.ERRORS.ACCOUNT_NUMBER; } return errors; } @@ -130,15 +130,15 @@ function validate(values) { let errors = {}; if (!ValidationUtils.isValidDisplayName(values.firstName)) { - errors = ErrorUtils.addErrorMessage(errors, 'firstName', props.translate('personalDetails.error.hasInvalidCharacter')); + errors = ErrorUtils.addErrorMessage(errors, 'firstName', 'personalDetails.error.hasInvalidCharacter'); } if (ValidationUtils.doesContainReservedWord(values.firstName, CONST.DISPLAY_NAME.RESERVED_FIRST_NAMES)) { - errors = ErrorUtils.addErrorMessage(errors, 'firstName', props.translate('personalDetails.error.containsReservedWord')); + errors = ErrorUtils.addErrorMessage(errors, 'firstName', 'personalDetails.error.containsReservedWord'); } if (!ValidationUtils.isValidDisplayName(values.lastName)) { - errors.lastName = props.translate('personalDetails.error.hasInvalidCharacter'); + errors.lastName = 'personalDetails.error.hasInvalidCharacter'; } return errors; From 833fb8b9a5d83e3f98018a57a6733e9ca653af14 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 8 Jun 2023 07:06:43 +0100 Subject: [PATCH 038/100] Translate keys for multi-keys error --- src/libs/ErrorUtils.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/ErrorUtils.js b/src/libs/ErrorUtils.js index e4f1b7bff877..2e67581f67e5 100644 --- a/src/libs/ErrorUtils.js +++ b/src/libs/ErrorUtils.js @@ -2,6 +2,7 @@ import _ from 'underscore'; import lodashGet from 'lodash/get'; import CONST from '../CONST'; import DateUtils from './DateUtils'; +import * as Localize from "./Localize"; /** * @param {Object} response @@ -99,10 +100,13 @@ function addErrorMessage(errors, inputID, message) { if (!message || !inputID) { return; } + + const translatedMessage = Localize.translateIfPhraseKey(message); + if (_.isEmpty(errorList[inputID])) { - errorList[inputID] = message; + errorList[inputID] = translatedMessage; } else { - errorList[inputID] = `${errorList[inputID]}\n${message}`; + errorList[inputID] = `${errorList[inputID]}\n${translatedMessage}`; } } From 6c3365e5b3478d9e9e0c730e5902742c392e67d9 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Thu, 8 Jun 2023 07:07:19 +0100 Subject: [PATCH 039/100] Run prettier --- src/libs/ErrorUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ErrorUtils.js b/src/libs/ErrorUtils.js index 2e67581f67e5..268d0411050e 100644 --- a/src/libs/ErrorUtils.js +++ b/src/libs/ErrorUtils.js @@ -2,7 +2,7 @@ import _ from 'underscore'; import lodashGet from 'lodash/get'; import CONST from '../CONST'; import DateUtils from './DateUtils'; -import * as Localize from "./Localize"; +import * as Localize from './Localize'; /** * @param {Object} response From e097e7863980652c5ca359a095902d9031cbe22b Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 8 Jun 2023 17:59:50 +0700 Subject: [PATCH 040/100] fix tooltip --- .../HTMLRenderers/MentionUserRenderer.js | 14 ++++++++------ src/components/TextLink.js | 3 +++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js index 81f723e66aef..17285249c856 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js @@ -9,6 +9,7 @@ import htmlRendererPropTypes from './htmlRendererPropTypes'; import withCurrentUserPersonalDetails from '../../withCurrentUserPersonalDetails'; import personalDetailsPropType from '../../../pages/personalDetailsPropType'; import * as StyleUtils from '../../../styles/StyleUtils'; +import TextLink from "../../TextLink"; const propTypes = { ...htmlRendererPropTypes, @@ -30,22 +31,23 @@ const MentionUserRenderer = (props) => { const defaultRendererProps = _.omit(props, ['TDefaultRenderer', 'style']); // We need to remove the leading @ from data as it is not part of the login - const loginWhithoutLeadingAt = props.tnode.data.slice(1); + const loginWithoutLeadingAt = props.tnode.data.slice(1); - const isOurMention = loginWhithoutLeadingAt === props.currentUserPersonalDetails.login; + const isOurMention = loginWithoutLeadingAt === props.currentUserPersonalDetails.login; return ( - - + showUserDetails(loginWhithoutLeadingAt)} + onPress={() => showUserDetails(loginWithoutLeadingAt)} > - + ); diff --git a/src/components/TextLink.js b/src/components/TextLink.js index f075002058ab..fcc37d0e9499 100644 --- a/src/components/TextLink.js +++ b/src/components/TextLink.js @@ -31,6 +31,7 @@ const defaultProps = { }; const TextLink = (props) => { + const rest = _.omit(props, _.keys(propTypes)); const additionalStyles = _.isArray(props.style) ? props.style : [props.style]; /** @@ -64,6 +65,8 @@ const TextLink = (props) => { onPress={openLink} onMouseDown={props.onMouseDown} onKeyDown={openLinkIfEnterKeyPressed} + // eslint-disable-next-line react/jsx-props-no-spreading + {...rest} > {props.children} From 1e5b7d62d8b2dd4aab012f981875ae8e96eb2419 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Thu, 8 Jun 2023 16:18:56 +0500 Subject: [PATCH 041/100] fix: clear storage on log out --- ios/Podfile.lock | 12 ++++-- package-lock.json | 38 +++++++++++++++++++ package.json | 1 + .../actions/Session/clearStorage/index.js | 6 +++ .../Session/clearStorage/index.native.js | 11 ++++++ src/libs/actions/Session/index.js | 5 ++- 6 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 src/libs/actions/Session/clearStorage/index.js create mode 100644 src/libs/actions/Session/clearStorage/index.native.js diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 6cb4235c58c8..80ba0e0b5b79 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -662,6 +662,8 @@ PODS: - Firebase/Performance (= 8.8.0) - React-Core - RNFBApp + - RNFS (2.20.0): + - React-Core - RNGestureHandler (2.9.0): - React-Core - RNLocalize (2.2.6): @@ -809,6 +811,7 @@ DEPENDENCIES: - "RNFBApp (from `../node_modules/@react-native-firebase/app`)" - "RNFBCrashlytics (from `../node_modules/@react-native-firebase/crashlytics`)" - "RNFBPerf (from `../node_modules/@react-native-firebase/perf`)" + - RNFS (from `../node_modules/react-native-fs`) - RNGestureHandler (from `../node_modules/react-native-gesture-handler`) - RNLocalize (from `../node_modules/react-native-localize`) - RNPermissions (from `../node_modules/react-native-permissions`) @@ -999,6 +1002,8 @@ EXTERNAL SOURCES: :path: "../node_modules/@react-native-firebase/crashlytics" RNFBPerf: :path: "../node_modules/@react-native-firebase/perf" + RNFS: + :path: "../node_modules/react-native-fs" RNGestureHandler: :path: "../node_modules/react-native-gesture-handler" RNLocalize: @@ -1019,7 +1024,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Airship: c70eed50e429f97f5adb285423c7291fb7a032ae AirshipFrameworkProxy: 7bc4130c668c6c98e2d4c60fe4c9eb61a999be99 - boost: a7c83b31436843459a1961bfd74b96033dc77234 + boost: 57d2868c099736d80fcd648bf211b4431e51a558 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: ff54429f0110d3c722630a98096ba689c39f6d5f @@ -1062,7 +1067,7 @@ SPEC CHECKSUMS: Permission-LocationWhenInUse: 3ba99e45c852763f730eabecec2870c2382b7bd4 Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2 PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef - RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda + RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 RCTRequired: e9e7b8b45aa9bedb2fdad71740adf07a7265b9be RCTTypeSafety: 9ae0e9206625e995f0df4d5b9ddc94411929fb30 React: a71c8e1380f07e01de721ccd52bcf9c03e81867d @@ -1120,6 +1125,7 @@ SPEC CHECKSUMS: RNFBApp: 729c0666395b1953198dc4a1ec6deb8fbe1c302e RNFBCrashlytics: 2061ca863e8e2fa1aae9b12477d7dfa8e88ca0f9 RNFBPerf: 389914cda4000fe0d996a752532a591132cbf3f9 + RNFS: 4ac0f0ea233904cb798630b3c077808c06931688 RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39 RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81 RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c @@ -1135,4 +1141,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 4ed1c7b099741c82e2b0411b95f6468e72be6c76 -COCOAPODS: 1.12.0 +COCOAPODS: 1.11.3 diff --git a/package-lock.json b/package-lock.json index f39a002a5a57..a980147dd7f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,6 +68,7 @@ "react-native-device-info": "^10.3.0", "react-native-document-picker": "^8.0.0", "react-native-fast-image": "^8.6.3", + "react-native-fs": "^2.20.0", "react-native-gesture-handler": "2.9.0", "react-native-google-places-autocomplete": "git+https://github.com/Expensify/react-native-google-places-autocomplete.git#6f436a06a3018cb49750bb110b89df75f6a865d5", "react-native-haptic-feedback": "^1.13.0", @@ -36206,6 +36207,24 @@ "react-native": ">0.62.0" } }, + "node_modules/react-native-fs": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.20.0.tgz", + "integrity": "sha512-VkTBzs7fIDUiy/XajOSNk0XazFE9l+QlMAce7lGuebZcag5CnjszB+u4BdqzwaQOdcYb5wsJIsqq4kxInIRpJQ==", + "dependencies": { + "base-64": "^0.1.0", + "utf8": "^3.0.0" + }, + "peerDependencies": { + "react-native": "*", + "react-native-windows": "*" + }, + "peerDependenciesMeta": { + "react-native-windows": { + "optional": true + } + } + }, "node_modules/react-native-gesture-handler": { "version": "2.9.0", "license": "MIT", @@ -41385,6 +41404,11 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" + }, "node_modules/utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", @@ -67500,6 +67524,15 @@ "dev": true, "requires": {} }, + "react-native-fs": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/react-native-fs/-/react-native-fs-2.20.0.tgz", + "integrity": "sha512-VkTBzs7fIDUiy/XajOSNk0XazFE9l+QlMAce7lGuebZcag5CnjszB+u4BdqzwaQOdcYb5wsJIsqq4kxInIRpJQ==", + "requires": { + "base-64": "^0.1.0", + "utf8": "^3.0.0" + } + }, "react-native-gesture-handler": { "version": "2.9.0", "requires": { @@ -70847,6 +70880,11 @@ "version": "1.2.0", "requires": {} }, + "utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" + }, "utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", diff --git a/package.json b/package.json index bacfa85258a7..9b0567d0a072 100644 --- a/package.json +++ b/package.json @@ -103,6 +103,7 @@ "react-native-device-info": "^10.3.0", "react-native-document-picker": "^8.0.0", "react-native-fast-image": "^8.6.3", + "react-native-fs": "^2.20.0", "react-native-gesture-handler": "2.9.0", "react-native-google-places-autocomplete": "git+https://github.com/Expensify/react-native-google-places-autocomplete.git#6f436a06a3018cb49750bb110b89df75f6a865d5", "react-native-haptic-feedback": "^1.13.0", diff --git a/src/libs/actions/Session/clearStorage/index.js b/src/libs/actions/Session/clearStorage/index.js new file mode 100644 index 000000000000..b978fc487d73 --- /dev/null +++ b/src/libs/actions/Session/clearStorage/index.js @@ -0,0 +1,6 @@ + +function clearStorage () { + return new Promise((res) => res()); +} + +export default clearStorage; \ No newline at end of file diff --git a/src/libs/actions/Session/clearStorage/index.native.js b/src/libs/actions/Session/clearStorage/index.native.js new file mode 100644 index 000000000000..36f2db5ef698 --- /dev/null +++ b/src/libs/actions/Session/clearStorage/index.native.js @@ -0,0 +1,11 @@ +import {CachesDirectoryPath, DocumentDirectoryPath, unlink} from 'react-native-fs'; +import Log from '../../../Log'; + +function clearStorage () { + return Promise.all( + unlink(DocumentDirectoryPath).catch(Log.debug), + unlink(CachesDirectoryPath).catch(Log.debug) + ); +} + +export default clearStorage; \ No newline at end of file diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index 9cb3c127b287..9bc69761f181 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -2,6 +2,7 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; import lodashGet from 'lodash/get'; import {Linking} from 'react-native'; +import clearStorage from './clearStorage'; import ONYXKEYS from '../../../ONYXKEYS'; import redirectToSignIn from '../SignInRedirect'; import CONFIG from '../../../CONFIG'; @@ -72,7 +73,9 @@ function signOut() { partnerPassword: CONFIG.EXPENSIFY.PARTNER_PASSWORD, shouldRetry: false, }); - + clearStorage().then(() => { + Log.info('Cleared all storage data', true, {}, true); + }); Timing.clearData(); } From 32c192a9eea53b4abbd3e72e262d8fd533a2b424 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Thu, 8 Jun 2023 22:51:20 +0500 Subject: [PATCH 042/100] feat: remove cache directory only --- .../Session/{clearStorage => clearCache}/index.js | 1 - src/libs/actions/Session/clearCache/index.native.js | 7 +++++++ src/libs/actions/Session/clearStorage/index.native.js | 11 ----------- src/libs/actions/Session/index.js | 6 +++--- 4 files changed, 10 insertions(+), 15 deletions(-) rename src/libs/actions/Session/{clearStorage => clearCache}/index.js (98%) create mode 100644 src/libs/actions/Session/clearCache/index.native.js delete mode 100644 src/libs/actions/Session/clearStorage/index.native.js diff --git a/src/libs/actions/Session/clearStorage/index.js b/src/libs/actions/Session/clearCache/index.js similarity index 98% rename from src/libs/actions/Session/clearStorage/index.js rename to src/libs/actions/Session/clearCache/index.js index b978fc487d73..f1689867e654 100644 --- a/src/libs/actions/Session/clearStorage/index.js +++ b/src/libs/actions/Session/clearCache/index.js @@ -1,4 +1,3 @@ - function clearStorage () { return new Promise((res) => res()); } diff --git a/src/libs/actions/Session/clearCache/index.native.js b/src/libs/actions/Session/clearCache/index.native.js new file mode 100644 index 000000000000..ca5300c1c577 --- /dev/null +++ b/src/libs/actions/Session/clearCache/index.native.js @@ -0,0 +1,7 @@ +import {CachesDirectoryPath, unlink} from 'react-native-fs'; + +function clearStorage () { + return unlink(CachesDirectoryPath); +} + +export default clearStorage; \ No newline at end of file diff --git a/src/libs/actions/Session/clearStorage/index.native.js b/src/libs/actions/Session/clearStorage/index.native.js deleted file mode 100644 index 36f2db5ef698..000000000000 --- a/src/libs/actions/Session/clearStorage/index.native.js +++ /dev/null @@ -1,11 +0,0 @@ -import {CachesDirectoryPath, DocumentDirectoryPath, unlink} from 'react-native-fs'; -import Log from '../../../Log'; - -function clearStorage () { - return Promise.all( - unlink(DocumentDirectoryPath).catch(Log.debug), - unlink(CachesDirectoryPath).catch(Log.debug) - ); -} - -export default clearStorage; \ No newline at end of file diff --git a/src/libs/actions/Session/index.js b/src/libs/actions/Session/index.js index 9bc69761f181..8d34c5c4bffb 100644 --- a/src/libs/actions/Session/index.js +++ b/src/libs/actions/Session/index.js @@ -2,7 +2,7 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; import lodashGet from 'lodash/get'; import {Linking} from 'react-native'; -import clearStorage from './clearStorage'; +import clearCache from './clearCache'; import ONYXKEYS from '../../../ONYXKEYS'; import redirectToSignIn from '../SignInRedirect'; import CONFIG from '../../../CONFIG'; @@ -73,8 +73,8 @@ function signOut() { partnerPassword: CONFIG.EXPENSIFY.PARTNER_PASSWORD, shouldRetry: false, }); - clearStorage().then(() => { - Log.info('Cleared all storage data', true, {}, true); + clearCache().then(() => { + Log.info('Cleared all chache data', true, {}, true); }); Timing.clearData(); } From 89924ac6680ba3ad47b196507b177bfdd8d0307a Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Fri, 9 Jun 2023 00:04:08 +0500 Subject: [PATCH 043/100] fix: revert unwanted podfile changes --- ios/Podfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 80ba0e0b5b79..048eeca5f76f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1024,7 +1024,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Airship: c70eed50e429f97f5adb285423c7291fb7a032ae AirshipFrameworkProxy: 7bc4130c668c6c98e2d4c60fe4c9eb61a999be99 - boost: 57d2868c099736d80fcd648bf211b4431e51a558 + boost: a7c83b31436843459a1961bfd74b96033dc77234 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: ff54429f0110d3c722630a98096ba689c39f6d5f @@ -1067,7 +1067,7 @@ SPEC CHECKSUMS: Permission-LocationWhenInUse: 3ba99e45c852763f730eabecec2870c2382b7bd4 Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2 PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef - RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 + RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda RCTRequired: e9e7b8b45aa9bedb2fdad71740adf07a7265b9be RCTTypeSafety: 9ae0e9206625e995f0df4d5b9ddc94411929fb30 React: a71c8e1380f07e01de721ccd52bcf9c03e81867d @@ -1141,4 +1141,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 4ed1c7b099741c82e2b0411b95f6468e72be6c76 -COCOAPODS: 1.11.3 +COCOAPODS: 1.12.0 From 89b6355afa6df05d63c1fa236844e05242ea05e8 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Fri, 9 Jun 2023 00:08:05 +0500 Subject: [PATCH 044/100] fix: lint errors --- src/libs/actions/Session/clearCache/index.js | 4 ++-- src/libs/actions/Session/clearCache/index.native.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/Session/clearCache/index.js b/src/libs/actions/Session/clearCache/index.js index f1689867e654..9ccd0193cfbd 100644 --- a/src/libs/actions/Session/clearCache/index.js +++ b/src/libs/actions/Session/clearCache/index.js @@ -1,5 +1,5 @@ -function clearStorage () { +function clearStorage() { return new Promise((res) => res()); } -export default clearStorage; \ No newline at end of file +export default clearStorage; diff --git a/src/libs/actions/Session/clearCache/index.native.js b/src/libs/actions/Session/clearCache/index.native.js index ca5300c1c577..d6064b8ae941 100644 --- a/src/libs/actions/Session/clearCache/index.native.js +++ b/src/libs/actions/Session/clearCache/index.native.js @@ -1,7 +1,7 @@ import {CachesDirectoryPath, unlink} from 'react-native-fs'; -function clearStorage () { +function clearStorage() { return unlink(CachesDirectoryPath); } -export default clearStorage; \ No newline at end of file +export default clearStorage; From 0a89e1ccd93c798c59b4d859129aee2b0717a0a9 Mon Sep 17 00:00:00 2001 From: Oliver Wilks Date: Thu, 8 Jun 2023 20:18:01 +0100 Subject: [PATCH 045/100] Use Localize for renamed report action --- src/libs/SidebarUtils.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 87e8b97d0bd0..cbc881f69e57 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -300,7 +300,15 @@ function getOptionData(reportID) { } if ((result.isChatRoom || result.isPolicyExpenseChat || result.isThread || result.isTaskReport) && !result.isArchivedRoom) { - result.alternateText = lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet'); + const lastAction = visibleReportActionItems[report.reportID] + if (lastAction && lastAction.actionName && lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) { + const displayName = lastActorDetails && lastActorDetails.login === currentUserLogin.email ? `${Localize.translate(preferredLocale, 'common.you')}` : `${lastActorDetails.displayName}`; + const oldName = lodashGet(lastAction, 'originalMessage.oldName', ''); + const newName = lodashGet(lastAction, 'originalMessage.newName', ''); + result.alternateText = displayName + Localize.translate(preferredLocale, 'newRoomPage.renamedRoomAction', {oldName, newName}) + } else { + result.alternateText = lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet'); + } } else { if (!lastMessageText) { // Here we get the beginning of chat history message and append the display name for each user, adding pronouns if there are any. From bca944b52d08351cf02a9d00f07b92ed8707a863 Mon Sep 17 00:00:00 2001 From: Oliver Wilks Date: Thu, 8 Jun 2023 20:31:19 +0100 Subject: [PATCH 046/100] Run prettier --- src/libs/SidebarUtils.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index cbc881f69e57..d3d0594a0869 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -300,12 +300,13 @@ function getOptionData(reportID) { } if ((result.isChatRoom || result.isPolicyExpenseChat || result.isThread || result.isTaskReport) && !result.isArchivedRoom) { - const lastAction = visibleReportActionItems[report.reportID] + const lastAction = visibleReportActionItems[report.reportID]; if (lastAction && lastAction.actionName && lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) { - const displayName = lastActorDetails && lastActorDetails.login === currentUserLogin.email ? `${Localize.translate(preferredLocale, 'common.you')}` : `${lastActorDetails.displayName}`; + const displayName = + lastActorDetails && lastActorDetails.login === currentUserLogin.email ? `${Localize.translate(preferredLocale, 'common.you')}` : `${lastActorDetails.displayName}`; const oldName = lodashGet(lastAction, 'originalMessage.oldName', ''); const newName = lodashGet(lastAction, 'originalMessage.newName', ''); - result.alternateText = displayName + Localize.translate(preferredLocale, 'newRoomPage.renamedRoomAction', {oldName, newName}) + result.alternateText = displayName + Localize.translate(preferredLocale, 'newRoomPage.renamedRoomAction', {oldName, newName}); } else { result.alternateText = lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet'); } From 1210ec9e46c56a11ab712e388ed06b6fbce2a893 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Fri, 9 Jun 2023 00:39:49 +0500 Subject: [PATCH 047/100] fix: failing unit tests --- jest/setup.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jest/setup.js b/jest/setup.js index 228f3a22f33b..f03c53540359 100644 --- a/jest/setup.js +++ b/jest/setup.js @@ -25,3 +25,9 @@ jest.spyOn(console, 'debug').mockImplementation((...params) => { // eslint-disable-next-line no-console console.log('DEBUG', ...params); }); + +// This mock is required for mocking file systems when running tests +jest.mock('react-native-fs', () => ({ + unlink: jest.fn(() => new Promise((res) => res())), + CachesDirectoryPath: jest.fn(), +})); From d055bd1746508945832b8db19b28f6e5a13b4616 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Fri, 9 Jun 2023 07:04:28 +0100 Subject: [PATCH 048/100] update error message propType --- src/components/DotIndicatorMessage.js | 2 +- src/components/FormHelpMessage.js | 2 +- src/components/RoomNameInput/roomNameInputPropTypes.js | 2 +- src/components/TextInput/baseTextInputPropTypes.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index 70304ac437e4..0240be813664 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -17,7 +17,7 @@ const propTypes = { * timestamp: 'message', * } */ - messages: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.array, PropTypes.string])), + messages: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object]))])), // The type of message, 'error' shows a red dot, 'success' shows a green dot type: PropTypes.oneOf(['error', 'success']).isRequired, diff --git a/src/components/FormHelpMessage.js b/src/components/FormHelpMessage.js index 1463b8ca745d..f85eac2843ca 100644 --- a/src/components/FormHelpMessage.js +++ b/src/components/FormHelpMessage.js @@ -12,7 +12,7 @@ import * as Localize from '../libs/Localize'; const propTypes = { /** Error or hint text. Ignored when children is not empty */ - message: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), + message: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object]))]), /** Children to render next to dot indicator */ children: PropTypes.node, diff --git a/src/components/RoomNameInput/roomNameInputPropTypes.js b/src/components/RoomNameInput/roomNameInputPropTypes.js index 453a986fdd1f..de233b8d96d6 100644 --- a/src/components/RoomNameInput/roomNameInputPropTypes.js +++ b/src/components/RoomNameInput/roomNameInputPropTypes.js @@ -12,7 +12,7 @@ const propTypes = { disabled: PropTypes.bool, /** Error text to show */ - errorText: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), + errorText: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object]))]), ...withLocalizePropTypes, diff --git a/src/components/TextInput/baseTextInputPropTypes.js b/src/components/TextInput/baseTextInputPropTypes.js index fb88d689be86..2e278bab5d69 100644 --- a/src/components/TextInput/baseTextInputPropTypes.js +++ b/src/components/TextInput/baseTextInputPropTypes.js @@ -17,7 +17,7 @@ const propTypes = { placeholder: PropTypes.string, /** Error text to display */ - errorText: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), + errorText: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object]))]), /** Icon to display in right side of text input */ icon: PropTypes.func, From 1d0ec86820b9ba1d007cc5209b86c77eba857faa Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 9 Jun 2023 15:22:00 +0700 Subject: [PATCH 049/100] Add subtasks with avatar Signed-off-by: dukenv0307 --- src/libs/ReportUtils.js | 10 ++++++++++ src/libs/SidebarUtils.js | 5 ++--- src/pages/home/HeaderView.js | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 0d26ff733f7d..b25335f1ab30 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -767,6 +767,16 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false) return [actorIcon]; } + if(isTaskReport(report)){ + const ownerEmail = lodashGet(report, 'ownerEmail', ''); + const ownerIcon = { + source: UserUtils.getAvatar(lodashGet(personalDetails, [ownerEmail, 'avatar']), ownerEmail), + name: ownerEmail, + type: CONST.ICON_TYPE_AVATAR, + }; + + return [ownerIcon]; + } if (isDomainRoom(report)) { result.source = Expensicons.DomainRoomAvatar; return [result]; diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 87e8b97d0bd0..ff077921e66e 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -237,7 +237,7 @@ function getOptionData(reportID) { result.isThread = ReportUtils.isThread(report); result.isChatRoom = ReportUtils.isChatRoom(report); - result.isTaskReport = ReportUtils.isTaskReport(report); +result.isTaskReport = ReportUtils.isTaskReport(report); result.isArchivedRoom = ReportUtils.isArchivedRoom(report); result.isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(report); result.isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); @@ -256,7 +256,6 @@ function getOptionData(reportID) { result.tooltipText = ReportUtils.getReportParticipantsTitle(report.participants || []); result.hasOutstandingIOU = report.hasOutstandingIOU; result.parentReportID = report.parentReportID || null; - const parentReport = result.parentReportID ? allReports[`${ONYXKEYS.COLLECTION.REPORT}${result.parentReportID}`] : null; const hasMultipleParticipants = participantPersonalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat; const subtitle = ReportUtils.getChatRoomSubtitle(report); @@ -340,7 +339,7 @@ function getOptionData(reportID) { result.subtitle = subtitle; result.participantsList = participantPersonalDetailList; - result.icons = ReportUtils.getIcons(result.isTaskReport ? parentReport : report, personalDetails, UserUtils.getAvatar(personalDetail.avatar, personalDetail.login), true); + result.icons = ReportUtils.getIcons(report, personalDetails, UserUtils.getAvatar(personalDetail.avatar, personalDetail.login), true); result.searchText = OptionsListUtils.getSearchText(report, reportName, participantPersonalDetailList, result.isChatRoom || result.isPolicyExpenseChat, result.isThread); result.displayNamesWithTooltips = displayNamesWithTooltips; return result; diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index c6f312574394..67d22efbc199 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -76,7 +76,7 @@ const HeaderView = (props) => { const isChatRoom = ReportUtils.isChatRoom(props.report); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.report); const isTaskReport = ReportUtils.isTaskReport(props.report); - const reportHeaderData = (isTaskReport || !isThread) && props.report.parentReportID ? props.parentReport : props.report; + const reportHeaderData = !isThread && props.report.parentReportID ? props.parentReport : props.report; const title = ReportUtils.getReportName(reportHeaderData); const subtitle = ReportUtils.getChatRoomSubtitle(reportHeaderData, props.parentReport); const isConcierge = participants.length === 1 && _.contains(participants, CONST.EMAIL.CONCIERGE); From e914b930af757a6e4623328f4efbbb3c73761ab1 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 9 Jun 2023 17:08:38 +0700 Subject: [PATCH 050/100] fix header view display --- src/pages/home/HeaderView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 67d22efbc199..bb9a3b43b9e8 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -76,7 +76,7 @@ const HeaderView = (props) => { const isChatRoom = ReportUtils.isChatRoom(props.report); const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(props.report); const isTaskReport = ReportUtils.isTaskReport(props.report); - const reportHeaderData = !isThread && props.report.parentReportID ? props.parentReport : props.report; + const reportHeaderData = !isTaskReport && !isThread && props.report.parentReportID ? props.parentReport : props.report; const title = ReportUtils.getReportName(reportHeaderData); const subtitle = ReportUtils.getChatRoomSubtitle(reportHeaderData, props.parentReport); const isConcierge = participants.length === 1 && _.contains(participants, CONST.EMAIL.CONCIERGE); From 70001fda12c8ef00986ee55da75fe81fcc513e43 Mon Sep 17 00:00:00 2001 From: Oliver Wilks Date: Fri, 9 Jun 2023 13:18:44 +0100 Subject: [PATCH 051/100] Translate 'You' in room rename action --- src/components/ReportActionItem/RenameAction.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/RenameAction.js b/src/components/ReportActionItem/RenameAction.js index b444e705adbe..cb5c90188de9 100644 --- a/src/components/ReportActionItem/RenameAction.js +++ b/src/components/ReportActionItem/RenameAction.js @@ -5,16 +5,22 @@ import Text from '../Text'; import styles from '../../styles/styles'; import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes'; import withLocalize, {withLocalizePropTypes} from '../withLocalize'; +import compose from '../../libs/compose'; +import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../withCurrentUserPersonalDetails'; const propTypes = { /** All the data of the action */ action: PropTypes.shape(reportActionPropTypes).isRequired, ...withLocalizePropTypes, + ...withCurrentUserPersonalDetailsPropTypes, }; const RenameAction = (props) => { - const displayName = lodashGet(props.action, ['message', 0, 'text']); + const currentUserLogin = props.currentUserPersonalDetails.login; + const userDisplayName = lodashGet(props.action, ['person', 0, 'text']); + const actorEmail = lodashGet(props.action, 'actorEmail', ''); + const displayName = actorEmail === currentUserLogin ? `${props.translate('common.you')}` : `${userDisplayName}`; const oldName = lodashGet(props.action, 'originalMessage.oldName', ''); const newName = lodashGet(props.action, 'originalMessage.newName', ''); @@ -29,4 +35,4 @@ const RenameAction = (props) => { RenameAction.propTypes = propTypes; RenameAction.displayName = 'RenameAction'; -export default withLocalize(RenameAction); +export default compose(withLocalize, withCurrentUserPersonalDetails)(RenameAction); From 917e7b63802876d6591c79e77fb5832fd72b45f7 Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Fri, 9 Jun 2023 09:35:00 -0500 Subject: [PATCH 052/100] fix: copy icon in contact-methods & workspace-reimbursements page on android(magic numberOfLines) --- src/components/PressableWithDelayToggle.js | 3 ++- src/pages/settings/Profile/Contacts/ContactMethodsPage.js | 3 ++- src/pages/workspace/reimburse/WorkspaceReimburseView.js | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/PressableWithDelayToggle.js b/src/components/PressableWithDelayToggle.js index 57f561ec91ac..f29345ef8d95 100644 --- a/src/components/PressableWithDelayToggle.js +++ b/src/components/PressableWithDelayToggle.js @@ -98,9 +98,10 @@ function PressableWithDelayToggle(props) { <> {props.isDelayButtonStateComplete && props.textChecked ? props.textChecked : props.text} +   { /> - + {/* Tricky fix with magic number. Should be fixed in main repo */} + {props.translate('contacts.helpTextBeforeEmail')} - + {/* Tricky fix with magic number. Should be fixed in main repo */} + {this.props.translate('workspace.reimburse.captureNoVBACopyBeforeEmail')} Date: Fri, 9 Jun 2023 09:42:45 -0500 Subject: [PATCH 053/100] fix: social icons refactor --- .../GenericPressable/BaseGenericPressable.js | 2 +- src/pages/signin/Socials.js | 44 ++++++++++--------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/components/Pressable/GenericPressable/BaseGenericPressable.js b/src/components/Pressable/GenericPressable/BaseGenericPressable.js index 6cdb83bbb81a..a31192a9e2a6 100644 --- a/src/components/Pressable/GenericPressable/BaseGenericPressable.js +++ b/src/components/Pressable/GenericPressable/BaseGenericPressable.js @@ -135,7 +135,7 @@ const GenericPressable = forwardRef((props, ref) => { return ( ( - + {_.map(socialsList, (social) => ( - - {(hovered) => ( - - - - - + { + e.preventDefault(); + Link.openExternalLink(social.link); + }} + accessible={false} + style={[styles.mr1, styles.mt1]} + shouldUseAutoHitSlop={false} + > + {({hovered, pressed}) => ( + )} - + ))} - + ); Socials.displayName = 'Socials'; From c5eb20d6be0d33647a527ebd17e2b5a2c77fb117 Mon Sep 17 00:00:00 2001 From: Oliver Wilks Date: Fri, 9 Jun 2023 15:58:53 +0100 Subject: [PATCH 054/100] Added roomRenamedTo translation key --- src/languages/en.js | 1 + src/languages/es.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/languages/en.js b/src/languages/en.js index 4602931ff120..cdcbf4f72641 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -1244,6 +1244,7 @@ export default { pleaseEnterRoomName: 'Please enter a room name', pleaseSelectWorkspace: 'Please select a workspace', renamedRoomAction: ({oldName, newName}) => ` renamed this room from ${oldName} to ${newName}`, + roomRenamedTo: ({newName}) => `Room renamed to ${newName}`, social: 'social', selectAWorkspace: 'Select a workspace', growlMessageOnRenameError: 'Unable to rename policy room, please check your connection and try again.', diff --git a/src/languages/es.js b/src/languages/es.js index a787607c465d..a3fae51d40ee 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -1250,6 +1250,7 @@ export default { pleaseEnterRoomName: 'Por favor, escribe el nombre de una sala', pleaseSelectWorkspace: 'Por favor, selecciona un espacio de trabajo', renamedRoomAction: ({oldName, newName}) => ` cambió el nombre de la sala de ${oldName} a ${newName}`, + roomRenamedTo: ({newName}) => `Sala renombrada a ${newName}`, social: 'social', selectAWorkspace: 'Seleccionar un espacio de trabajo', growlMessageOnRenameError: 'No se ha podido cambiar el nombre del espacio de trabajo, por favor, comprueba tu conexión e inténtalo de nuevo.', From 291c6679aefb4190f1155a7750391aee34f31148 Mon Sep 17 00:00:00 2001 From: Oliver Wilks Date: Fri, 9 Jun 2023 15:59:39 +0100 Subject: [PATCH 055/100] Implemented roomRenamedTo translation key --- src/libs/SidebarUtils.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index d3d0594a0869..11e960c7da01 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -302,11 +302,8 @@ function getOptionData(reportID) { if ((result.isChatRoom || result.isPolicyExpenseChat || result.isThread || result.isTaskReport) && !result.isArchivedRoom) { const lastAction = visibleReportActionItems[report.reportID]; if (lastAction && lastAction.actionName && lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) { - const displayName = - lastActorDetails && lastActorDetails.login === currentUserLogin.email ? `${Localize.translate(preferredLocale, 'common.you')}` : `${lastActorDetails.displayName}`; - const oldName = lodashGet(lastAction, 'originalMessage.oldName', ''); const newName = lodashGet(lastAction, 'originalMessage.newName', ''); - result.alternateText = displayName + Localize.translate(preferredLocale, 'newRoomPage.renamedRoomAction', {oldName, newName}); + result.alternateText = Localize.translate(preferredLocale, 'newRoomPage.roomRenamedTo', {newName}); } else { result.alternateText = lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet'); } From 975952d036fd0713122691849e071f4328033ae4 Mon Sep 17 00:00:00 2001 From: ahmedGaber93 Date: Fri, 9 Jun 2023 23:23:22 +0200 Subject: [PATCH 056/100] fix welcome message input auto focused --- src/pages/ReportWelcomeMessagePage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/ReportWelcomeMessagePage.js b/src/pages/ReportWelcomeMessagePage.js index 6d7a69f8de92..7f5a1a810130 100644 --- a/src/pages/ReportWelcomeMessagePage.js +++ b/src/pages/ReportWelcomeMessagePage.js @@ -48,7 +48,7 @@ function ReportWelcomeMessagePage(props) { return ( { + onEntryTransitionEnd={() => { if (!welcomeMessageInputRef.current) { return; } @@ -73,7 +73,7 @@ function ReportWelcomeMessagePage(props) { multiline numberOfLines={10} maxLength={CONST.MAX_COMMENT_LENGTH} - ref={welcomeMessageInputRef} + ref={(el) => (welcomeMessageInputRef.current = el)} value={welcomeMessage} onChangeText={handleWelcomeMessageChange} autoCapitalize="none" From f2ba642ebf75868161957824aeddca84f44fdfc7 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Sat, 10 Jun 2023 18:17:22 +0700 Subject: [PATCH 057/100] fix lint --- src/libs/ReportUtils.js | 2 +- src/libs/SidebarUtils.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index b25335f1ab30..233468bddbf0 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -767,7 +767,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false) return [actorIcon]; } - if(isTaskReport(report)){ + if (isTaskReport(report)) { const ownerEmail = lodashGet(report, 'ownerEmail', ''); const ownerIcon = { source: UserUtils.getAvatar(lodashGet(personalDetails, [ownerEmail, 'avatar']), ownerEmail), diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index ff077921e66e..baa42653a963 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -237,7 +237,7 @@ function getOptionData(reportID) { result.isThread = ReportUtils.isThread(report); result.isChatRoom = ReportUtils.isChatRoom(report); -result.isTaskReport = ReportUtils.isTaskReport(report); + result.isTaskReport = ReportUtils.isTaskReport(report); result.isArchivedRoom = ReportUtils.isArchivedRoom(report); result.isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(report); result.isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report); From 13befdd3629c3eb70cdaa959bde06c9d15c16d4d Mon Sep 17 00:00:00 2001 From: Oliver Wilks Date: Sat, 10 Jun 2023 18:02:03 +0100 Subject: [PATCH 058/100] Use accountID in RenameAction --- src/components/ReportActionItem/RenameAction.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/RenameAction.js b/src/components/ReportActionItem/RenameAction.js index cb5c90188de9..488189bae2ee 100644 --- a/src/components/ReportActionItem/RenameAction.js +++ b/src/components/ReportActionItem/RenameAction.js @@ -17,10 +17,10 @@ const propTypes = { }; const RenameAction = (props) => { - const currentUserLogin = props.currentUserPersonalDetails.login; + const currentUserAccountID = props.currentUserPersonalDetails.accountID; const userDisplayName = lodashGet(props.action, ['person', 0, 'text']); - const actorEmail = lodashGet(props.action, 'actorEmail', ''); - const displayName = actorEmail === currentUserLogin ? `${props.translate('common.you')}` : `${userDisplayName}`; + const actorAccountID = lodashGet(props.action, 'actorAccountID', ''); + const displayName = actorAccountID === currentUserAccountID ? `${props.translate('common.you')}` : `${userDisplayName}`; const oldName = lodashGet(props.action, 'originalMessage.oldName', ''); const newName = lodashGet(props.action, 'originalMessage.newName', ''); From 7b640764933078fa8bc28df8c4a5d71c7118554c Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 12 Jun 2023 11:15:42 +0700 Subject: [PATCH 059/100] fix lint --- .../HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js index 17285249c856..9feb77f88c82 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js +++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js @@ -9,7 +9,7 @@ import htmlRendererPropTypes from './htmlRendererPropTypes'; import withCurrentUserPersonalDetails from '../../withCurrentUserPersonalDetails'; import personalDetailsPropType from '../../../pages/personalDetailsPropType'; import * as StyleUtils from '../../../styles/StyleUtils'; -import TextLink from "../../TextLink"; +import TextLink from '../../TextLink'; const propTypes = { ...htmlRendererPropTypes, From a3dc3ede2cad1288973281a61ce464da7d041cb5 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Mon, 12 Jun 2023 07:44:23 +0100 Subject: [PATCH 060/100] [Fix] use error key from form's validate method --- src/pages/workspace/WorkspaceNewRoomPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index 5a23a093bf14..fd91d1b43214 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -114,7 +114,7 @@ class WorkspaceNewRoomPage extends React.Component { } if (!values.policyID) { - errors.policyID = this.props.translate('newRoomPage.pleaseSelectWorkspace'); + errors.policyID = 'newRoomPage.pleaseSelectWorkspace'; } return errors; From 208a55ea9740b0b69537e1d3bf0e3c47c3b73cef Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Mon, 12 Jun 2023 08:38:36 +0100 Subject: [PATCH 061/100] Optimize translated multiline errors --- src/libs/ErrorUtils.js | 4 ++-- src/libs/Localize/index.js | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/libs/ErrorUtils.js b/src/libs/ErrorUtils.js index 268d0411050e..12b81fc36004 100644 --- a/src/libs/ErrorUtils.js +++ b/src/libs/ErrorUtils.js @@ -104,9 +104,9 @@ function addErrorMessage(errors, inputID, message) { const translatedMessage = Localize.translateIfPhraseKey(message); if (_.isEmpty(errorList[inputID])) { - errorList[inputID] = translatedMessage; + errorList[inputID] = [translatedMessage, {isTranslated: true}]; } else { - errorList[inputID] = `${errorList[inputID]}\n${translatedMessage}`; + errorList[inputID][0] = `${errorList[inputID][0]}\n${translatedMessage}`; } } diff --git a/src/libs/Localize/index.js b/src/libs/Localize/index.js index acbedc4b586f..72d552099f78 100644 --- a/src/libs/Localize/index.js +++ b/src/libs/Localize/index.js @@ -101,6 +101,13 @@ function translateIfPhraseKey(message) { try { // check if error message has a variable parameter const [phrase, variables] = _.isArray(message) ? message : [message]; + + // This condition checks if the error is already translated. For example, if there are multiple errors per input, we handle translation in ErrorUtils.addErrorMessage due to the inability to concatenate error keys. + + if (variables && variables.isTranslated) { + return phrase; + } + return translateLocal(phrase, variables); } catch (error) { return message; From a139e7714fbd9d84e94cd0b5be7d7fc8595b77e0 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Mon, 12 Jun 2023 09:17:52 +0100 Subject: [PATCH 062/100] Simplify code and Fix tests --- src/libs/ErrorUtils.js | 4 +++- tests/unit/ErrorUtilsTest.js | 13 ++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/libs/ErrorUtils.js b/src/libs/ErrorUtils.js index 12b81fc36004..fdeae7809f58 100644 --- a/src/libs/ErrorUtils.js +++ b/src/libs/ErrorUtils.js @@ -96,15 +96,17 @@ function getLatestErrorField(onyxData, fieldName) { * */ function addErrorMessage(errors, inputID, message) { - const errorList = errors; if (!message || !inputID) { return; } + const errorList = errors; const translatedMessage = Localize.translateIfPhraseKey(message); if (_.isEmpty(errorList[inputID])) { errorList[inputID] = [translatedMessage, {isTranslated: true}]; + } else if (_.isString(errorList[inputID])) { + errorList[inputID] = [`${errorList[inputID]}\n${translatedMessage}`, {isTranslated: true}]; } else { errorList[inputID][0] = `${errorList[inputID][0]}\n${translatedMessage}`; } diff --git a/tests/unit/ErrorUtilsTest.js b/tests/unit/ErrorUtilsTest.js index b1bc3e6cdf25..7a46c71a1aa1 100644 --- a/tests/unit/ErrorUtilsTest.js +++ b/tests/unit/ErrorUtilsTest.js @@ -5,21 +5,21 @@ describe('ErrorUtils', () => { const errors = {}; ErrorUtils.addErrorMessage(errors, 'username', 'Username cannot be empty'); - expect(errors).toEqual({username: 'Username cannot be empty'}); + expect(errors).toEqual({username: ['Username cannot be empty', {isTranslated: true}]}); }); test('should append an error message to an existing error message for a given inputID', () => { const errors = {username: 'Username cannot be empty'}; ErrorUtils.addErrorMessage(errors, 'username', 'Username must be at least 6 characters long'); - expect(errors).toEqual({username: 'Username cannot be empty\nUsername must be at least 6 characters long'}); + expect(errors).toEqual({username: ['Username cannot be empty\nUsername must be at least 6 characters long', {isTranslated: true}]}); }); test('should add an error to input which does not contain any errors yet', () => { const errors = {username: 'Username cannot be empty'}; ErrorUtils.addErrorMessage(errors, 'password', 'Password cannot be empty'); - expect(errors).toEqual({username: 'Username cannot be empty', password: 'Password cannot be empty'}); + expect(errors).toEqual({username: 'Username cannot be empty', password: ['Password cannot be empty', {isTranslated: true}]}); }); test('should not mutate the errors object when message is empty', () => { @@ -49,7 +49,7 @@ describe('ErrorUtils', () => { ErrorUtils.addErrorMessage(errors, 'username', 'Username must be at least 6 characters long'); ErrorUtils.addErrorMessage(errors, 'username', 'Username must contain at least one letter'); - expect(errors).toEqual({username: 'Username cannot be empty\nUsername must be at least 6 characters long\nUsername must contain at least one letter'}); + expect(errors).toEqual({username: ['Username cannot be empty\nUsername must be at least 6 characters long\nUsername must contain at least one letter', {isTranslated: true}]}); }); test('should append multiple error messages to an existing error message for the same inputID', () => { @@ -58,7 +58,10 @@ describe('ErrorUtils', () => { ErrorUtils.addErrorMessage(errors, 'username', 'Username must not contain special characters'); expect(errors).toEqual({ - username: 'Username cannot be empty\nUsername must be at least 6 characters long\nUsername must contain at least one letter\nUsername must not contain special characters', + username: [ + 'Username cannot be empty\nUsername must be at least 6 characters long\nUsername must contain at least one letter\nUsername must not contain special characters', + {isTranslated: true}, + ], }); }); }); From 4b1f35b14e63ef44cced4f1c12797f493e69f9cd Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Mon, 12 Jun 2023 12:15:10 +0100 Subject: [PATCH 063/100] Fix - use key instead of translated string --- src/components/Form.js | 6 +++--- src/libs/Localize/index.js | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/Form.js b/src/components/Form.js index 578081ad0678..e034f9a27fd4 100644 --- a/src/components/Form.js +++ b/src/components/Form.js @@ -95,7 +95,7 @@ const Form = (props) => { const inputRefs = useRef({}); const touchedInputs = useRef({}); - const {validate, translate, onSubmit, children} = props; + const {validate, onSubmit, children} = props; /** * @param {Object} values - An object containing the value of each inputID, e.g. {inputID1: value1, inputID2: value2} @@ -126,7 +126,7 @@ const Form = (props) => { } // Add a validation error here because it is a string value that contains HTML characters - validationErrors[inputID] = translate('common.error.invalidCharacter'); + validationErrors[inputID] = 'common.error.invalidCharacter'; }); if (!_.isObject(validationErrors)) { @@ -141,7 +141,7 @@ const Form = (props) => { return touchedInputErrors; }, - [errors, touchedInputs, props.formID, validate, translate], + [errors, touchedInputs, props.formID, validate], ); useEffect(() => { diff --git a/src/libs/Localize/index.js b/src/libs/Localize/index.js index 72d552099f78..5d76347a9d83 100644 --- a/src/libs/Localize/index.js +++ b/src/libs/Localize/index.js @@ -98,6 +98,10 @@ function translateLocal(phrase, variables) { * @returns {String} */ function translateIfPhraseKey(message) { + if (!message) { + return ''; + } + try { // check if error message has a variable parameter const [phrase, variables] = _.isArray(message) ? message : [message]; From ff1729b7ade858b287deab7af4c5438fea6969ca Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Mon, 12 Jun 2023 13:53:25 +0100 Subject: [PATCH 064/100] [Fix] Handle empty message --- src/libs/Localize/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Localize/index.js b/src/libs/Localize/index.js index 5d76347a9d83..4941bc0949f5 100644 --- a/src/libs/Localize/index.js +++ b/src/libs/Localize/index.js @@ -98,7 +98,7 @@ function translateLocal(phrase, variables) { * @returns {String} */ function translateIfPhraseKey(message) { - if (!message) { + if (!_.isEmpty(message)) { return ''; } From 157df5b1034d7c9ca85261b17a9500b34a6f8ea0 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Mon, 12 Jun 2023 13:58:45 +0100 Subject: [PATCH 065/100] [Fix] Handle empty message --- src/libs/Localize/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Localize/index.js b/src/libs/Localize/index.js index 4941bc0949f5..9878873377b8 100644 --- a/src/libs/Localize/index.js +++ b/src/libs/Localize/index.js @@ -98,7 +98,7 @@ function translateLocal(phrase, variables) { * @returns {String} */ function translateIfPhraseKey(message) { - if (!_.isEmpty(message)) { + if (_.isEmpty(message)) { return ''; } From b31e76f8ff934eafc174486df2b26a9f7757403b Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Mon, 12 Jun 2023 19:31:18 +0530 Subject: [PATCH 066/100] use isFocusedRef for keeping latest value --- src/pages/home/report/ReportActionItemMessageEdit.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index 58345a885bc7..c0f3d0d592dc 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -95,6 +95,12 @@ function ReportActionItemMessageEdit(props) { const [hasExceededMaxCommentLength, setHasExceededMaxCommentLength] = useState(false); const textInputRef = useRef(null); + const isFocusedRef = useRef(false); + + useEffect(() => { + // required for keeping last state of isFocused variable + isFocusedRef.current = isFocused; + }, [isFocused]); useEffect(() => { // For mobile Safari, updating the selection prop on an unfocused input will cause it to automatically gain focus @@ -110,7 +116,7 @@ function ReportActionItemMessageEdit(props) { return () => { // Skip if this is not the focused message so the other edit composer stays focused - if (!textInputRef.current.isFocused()) { + if (!isFocusedRef.current) { return; } From 5467cd0b257e5d6b5102888a5751813d5f529963 Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Mon, 12 Jun 2023 21:14:40 +0530 Subject: [PATCH 067/100] removed comment --- src/pages/home/report/ReportActionItemMessageEdit.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index c0f3d0d592dc..cb50ad9f6f2c 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -124,7 +124,6 @@ function ReportActionItemMessageEdit(props) { // to prevent the main composer stays hidden until we swtich to another chat. ComposerActions.setShouldShowComposeInput(true); }; - // eslint-disable-next-line react-hooks/exhaustive-deps -- we need it to call it once on mount }, []); /** From b51cfe3a27582af2d3d576e821048f16f801f12c Mon Sep 17 00:00:00 2001 From: Oliver Wilks Date: Mon, 12 Jun 2023 16:56:27 +0100 Subject: [PATCH 068/100] Use lodashGet for currentUserAccountID --- src/components/ReportActionItem/RenameAction.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/RenameAction.js b/src/components/ReportActionItem/RenameAction.js index 488189bae2ee..176ad62ac40b 100644 --- a/src/components/ReportActionItem/RenameAction.js +++ b/src/components/ReportActionItem/RenameAction.js @@ -17,7 +17,7 @@ const propTypes = { }; const RenameAction = (props) => { - const currentUserAccountID = props.currentUserPersonalDetails.accountID; + const currentUserAccountID = lodashGet(props.currentUserPersonalDetails, 'accountID', ''); const userDisplayName = lodashGet(props.action, ['person', 0, 'text']); const actorAccountID = lodashGet(props.action, 'actorAccountID', ''); const displayName = actorAccountID === currentUserAccountID ? `${props.translate('common.you')}` : `${userDisplayName}`; From 51bdf0e7d5bc4742b304358427a605ae6eccdac4 Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Mon, 12 Jun 2023 12:31:56 -0500 Subject: [PATCH 069/100] fix: comments to workaround --- src/pages/settings/Profile/Contacts/ContactMethodsPage.js | 3 ++- src/pages/workspace/reimburse/WorkspaceReimburseView.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodsPage.js index 6e33ebd503c6..7ea6e788211c 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodsPage.js @@ -118,7 +118,8 @@ const ContactMethodsPage = (props) => { /> - {/* Tricky fix with magic number. Should be fixed in main repo */} + {/* Workaround to fix https://github.com/Expensify/App/issues/17368. + TODO: Remove `numberOfLines` once https://github.com/facebook/react-native/pull/35703 is merged and applied to our repo */} {props.translate('contacts.helpTextBeforeEmail')} - {/* Tricky fix with magic number. Should be fixed in main repo */} + {/* Workaround to fix https://github.com/Expensify/App/issues/17368. + TODO: Remove `numberOfLines` once https://github.com/facebook/react-native/pull/35703 is merged and applied to our repo */} {this.props.translate('workspace.reimburse.captureNoVBACopyBeforeEmail')} Date: Mon, 12 Jun 2023 21:08:34 +0100 Subject: [PATCH 070/100] Use lodashGet for actionName --- src/libs/SidebarUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 11e960c7da01..44b6fd425392 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -301,7 +301,7 @@ function getOptionData(reportID) { if ((result.isChatRoom || result.isPolicyExpenseChat || result.isThread || result.isTaskReport) && !result.isArchivedRoom) { const lastAction = visibleReportActionItems[report.reportID]; - if (lastAction && lastAction.actionName && lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) { + if (lodashGet(lastAction, 'actionName', '') === CONST.REPORT.ACTIONS.TYPE.RENAMED) { const newName = lodashGet(lastAction, 'originalMessage.newName', ''); result.alternateText = Localize.translate(preferredLocale, 'newRoomPage.roomRenamedTo', {newName}); } else { From 3d4eb92547fa119a5362c9816bfb59137caf353c Mon Sep 17 00:00:00 2001 From: Hans Date: Tue, 13 Jun 2023 10:59:12 +0700 Subject: [PATCH 071/100] upgrade expensify common --- package-lock.json | 55 ++++++++++++----------------------------------- package.json | 3 +-- 2 files changed, 15 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8fb2ed4970c8..cef8bc2ba52a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,9 +40,8 @@ "babel-polyfill": "^6.26.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#50aacd53fe54ef7131e5cb9c74ee4526b3bcfe16", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#743108fd2428945c5a75baa2a027b5a4ab407b5b", "fbjs": "^3.0.2", - "html-entities": "^1.3.1", "htmlparser2": "^7.2.0", "jest-when": "^3.5.2", "localforage": "^1.10.0", @@ -5335,11 +5334,6 @@ } } }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/html-entities": { - "version": "2.3.3", - "dev": true, - "license": "MIT" - }, "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": { "version": "0.7.4", "dev": true, @@ -24054,13 +24048,13 @@ }, "node_modules/expensify-common": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#50aacd53fe54ef7131e5cb9c74ee4526b3bcfe16", - "integrity": "sha512-wnx6WiG2NVqIs2m3M0VjL/kw2I1rgWOD06mNp6FwRGeOVC+QIL6hsdJgqf9z9NjBSuhc6THfzbcrAOSGs3kTkw==", + "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#743108fd2428945c5a75baa2a027b5a4ab407b5b", + "integrity": "sha512-RwY3fJGVDTanD9+shESDDHT4YCjQ9/hNtfOiWuoKNsTuJm5fkS/FPyh8kHj+gGm+6DzTtMPuRBsPDSKCFT8fXA==", "license": "MIT", "dependencies": { "classnames": "2.3.1", "clipboard": "2.0.4", - "html-entities": "^1.3.1", + "html-entities": "^2.3.3", "jquery": "3.6.0", "localforage": "^1.10.0", "lodash": "4.17.21", @@ -25878,8 +25872,9 @@ } }, "node_modules/html-entities": { - "version": "1.4.0", - "license": "MIT" + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.5.tgz", + "integrity": "sha512-72TJlcMkYsEJASa/3HnX7VT59htM7iSHbH59NSZbtc+22Ap0Txnlx91sfeB+/A7wNZg7UxtZdhAW4y+/jimrdg==" }, "node_modules/html-escaper": { "version": "2.0.2", @@ -42229,11 +42224,6 @@ "dev": true, "license": "MIT" }, - "node_modules/webpack-dev-server/node_modules/html-entities": { - "version": "2.3.3", - "dev": true, - "license": "MIT" - }, "node_modules/webpack-dev-server/node_modules/ipaddr.js": { "version": "2.0.1", "dev": true, @@ -42407,11 +42397,6 @@ "strip-ansi": "^6.0.0" } }, - "node_modules/webpack-hot-middleware/node_modules/html-entities": { - "version": "2.3.3", - "dev": true, - "license": "MIT" - }, "node_modules/webpack-log": { "version": "2.0.0", "dev": true, @@ -46530,10 +46515,6 @@ "source-map": "^0.7.3" }, "dependencies": { - "html-entities": { - "version": "2.3.3", - "dev": true - }, "source-map": { "version": "0.7.4", "dev": true @@ -59286,13 +59267,13 @@ } }, "expensify-common": { - "version": "git+ssh://git@github.com/Expensify/expensify-common.git#50aacd53fe54ef7131e5cb9c74ee4526b3bcfe16", - "integrity": "sha512-wnx6WiG2NVqIs2m3M0VjL/kw2I1rgWOD06mNp6FwRGeOVC+QIL6hsdJgqf9z9NjBSuhc6THfzbcrAOSGs3kTkw==", - "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#50aacd53fe54ef7131e5cb9c74ee4526b3bcfe16", + "version": "git+ssh://git@github.com/Expensify/expensify-common.git#743108fd2428945c5a75baa2a027b5a4ab407b5b", + "integrity": "sha512-RwY3fJGVDTanD9+shESDDHT4YCjQ9/hNtfOiWuoKNsTuJm5fkS/FPyh8kHj+gGm+6DzTtMPuRBsPDSKCFT8fXA==", + "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#743108fd2428945c5a75baa2a027b5a4ab407b5b", "requires": { "classnames": "2.3.1", "clipboard": "2.0.4", - "html-entities": "^1.3.1", + "html-entities": "^2.3.3", "jquery": "3.6.0", "localforage": "^1.10.0", "lodash": "4.17.21", @@ -60493,7 +60474,9 @@ } }, "html-entities": { - "version": "1.4.0" + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.5.tgz", + "integrity": "sha512-72TJlcMkYsEJASa/3HnX7VT59htM7iSHbH59NSZbtc+22Ap0Txnlx91sfeB+/A7wNZg7UxtZdhAW4y+/jimrdg==" }, "html-escaper": { "version": "2.0.2" @@ -71472,10 +71455,6 @@ "version": "2.0.19", "dev": true }, - "html-entities": { - "version": "2.3.3", - "dev": true - }, "ipaddr.js": { "version": "2.0.1", "dev": true @@ -71585,12 +71564,6 @@ "ansi-html-community": "0.0.8", "html-entities": "^2.1.0", "strip-ansi": "^6.0.0" - }, - "dependencies": { - "html-entities": { - "version": "2.3.3", - "dev": true - } } }, "webpack-log": { diff --git a/package.json b/package.json index f67ff783297f..4462f9d7ad68 100644 --- a/package.json +++ b/package.json @@ -76,9 +76,8 @@ "babel-polyfill": "^6.26.0", "dom-serializer": "^0.2.2", "domhandler": "^4.3.0", - "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#50aacd53fe54ef7131e5cb9c74ee4526b3bcfe16", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#743108fd2428945c5a75baa2a027b5a4ab407b5b", "fbjs": "^3.0.2", - "html-entities": "^1.3.1", "htmlparser2": "^7.2.0", "jest-when": "^3.5.2", "localforage": "^1.10.0", From d9cabaa9a5782903754600292a6c154c6f93ec1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Tue, 13 Jun 2023 09:25:06 +0200 Subject: [PATCH 072/100] removed repeating default dimming value --- src/components/Reactions/AddReactionBubble.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/Reactions/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.js index ecf63bd87747..9210fd423f6a 100644 --- a/src/components/Reactions/AddReactionBubble.js +++ b/src/components/Reactions/AddReactionBubble.js @@ -78,7 +78,6 @@ const AddReactionBubble = (props) => { accessibilityLabel={props.translate('emojiReactions.addReactionTooltip')} accessibilityRole="button" // disable dimming - hoverDimmingValue={1} pressDimmingValue={1} > {({hovered, pressed}) => ( From c601c5368243d0e9edfdad256c9456848c90360c Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 13 Jun 2023 16:23:52 +0700 Subject: [PATCH 073/100] fix: 20496 email is not cleared when open new contact method page --- src/libs/actions/User.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index b90a22ceac8a..12d98c664e7e 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -360,7 +360,7 @@ function addNewContactMethodAndNavigate(contactMethod, password) { ]; API.write('AddNewContactMethod', {partnerUserID: contactMethod, password}, {optimisticData, successData, failureData}); - Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS); + Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS); } /** From 26db64bc21d2507b4e235e1abfd26f0cb3ace37e Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 13 Jun 2023 06:33:24 -0500 Subject: [PATCH 074/100] fix: WorkspaceBillsFirstSectioin --- src/pages/workspace/bills/WorkspaceBillsFirstSection.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/bills/WorkspaceBillsFirstSection.js b/src/pages/workspace/bills/WorkspaceBillsFirstSection.js index 12cfa47aee11..e766070dfca5 100644 --- a/src/pages/workspace/bills/WorkspaceBillsFirstSection.js +++ b/src/pages/workspace/bills/WorkspaceBillsFirstSection.js @@ -61,9 +61,11 @@ const WorkspaceBillsFirstSection = (props) => { containerStyles={[styles.cardSection]} > - + {/* Workaround to fix https://github.com/Expensify/App/issues/17368. + TODO: Remove `numberOfLines` once https://github.com/facebook/react-native/pull/35703 is merged and applied to our repo */} + {props.translate('workspace.bills.askYourVendorsBeforeEmail')} - {props.user.isFromPublicDomain ? ( + {!props.user.isFromPublicDomain ? ( Link.openExternalLink('https://community.expensify.com/discussion/7500/how-to-pay-your-company-bills-in-expensify/')}> example.com@expensify.cash From 511db7ea6801be0ae3123be873c5137313131bff Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 13 Jun 2023 07:02:02 -0500 Subject: [PATCH 075/100] fix: mistake --- src/pages/workspace/bills/WorkspaceBillsFirstSection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/bills/WorkspaceBillsFirstSection.js b/src/pages/workspace/bills/WorkspaceBillsFirstSection.js index e766070dfca5..17100acc9fec 100644 --- a/src/pages/workspace/bills/WorkspaceBillsFirstSection.js +++ b/src/pages/workspace/bills/WorkspaceBillsFirstSection.js @@ -65,7 +65,7 @@ const WorkspaceBillsFirstSection = (props) => { TODO: Remove `numberOfLines` once https://github.com/facebook/react-native/pull/35703 is merged and applied to our repo */} {props.translate('workspace.bills.askYourVendorsBeforeEmail')} - {!props.user.isFromPublicDomain ? ( + {props.user.isFromPublicDomain ? ( Link.openExternalLink('https://community.expensify.com/discussion/7500/how-to-pay-your-company-bills-in-expensify/')}> example.com@expensify.cash From 67069641d39fe5fc7fd593e43c84af6547c38bc8 Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 13 Jun 2023 07:38:28 -0500 Subject: [PATCH 076/100] fix: reduce margin of social icons(parent) --- src/pages/signin/SignInPageLayout/Footer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/signin/SignInPageLayout/Footer.js b/src/pages/signin/SignInPageLayout/Footer.js index fb58f5292dd6..8c5c6fe1b3a9 100644 --- a/src/pages/signin/SignInPageLayout/Footer.js +++ b/src/pages/signin/SignInPageLayout/Footer.js @@ -191,7 +191,7 @@ const Footer = (props) => { ))} {i === 2 && ( - + )} From 655c630453db3f52fc8a9b0964bbc84e477d519a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Tue, 13 Jun 2023 14:38:53 +0200 Subject: [PATCH 077/100] migrated AttachmentView to PressableWithoutFeedback --- src/components/AttachmentView.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/AttachmentView.js b/src/components/AttachmentView.js index cf9814149322..89ddb28f6e4f 100755 --- a/src/components/AttachmentView.js +++ b/src/components/AttachmentView.js @@ -1,5 +1,5 @@ import React, {memo, useState} from 'react'; -import {View, ActivityIndicator, Pressable} from 'react-native'; +import {View, ActivityIndicator} from 'react-native'; import _ from 'underscore'; import PropTypes from 'prop-types'; import Str from 'expensify-common/lib/str'; @@ -15,6 +15,7 @@ import Tooltip from './Tooltip'; import themeColors from '../styles/themes/default'; import variables from '../styles/variables'; import addEncryptedAuthTokenToURL from '../libs/addEncryptedAuthTokenToURL'; +import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; const propTypes = { /** Whether source url requires authentication */ @@ -93,13 +94,15 @@ const AttachmentView = (props) => { /> ); return props.onPress ? ( - {children} - + ) : ( children ); @@ -117,13 +120,15 @@ const AttachmentView = (props) => { /> ); return props.onPress ? ( - {children} - + ) : ( children ); From f4238ab5fb48d5dcfb0ae31abcc3915a9d0d8fbe Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Wed, 14 Jun 2023 00:50:05 +0700 Subject: [PATCH 078/100] avoid using lodashGet --- 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 233468bddbf0..f5dde848f10d 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -768,7 +768,7 @@ function getIcons(report, personalDetails, defaultIcon = null, isPayer = false) return [actorIcon]; } if (isTaskReport(report)) { - const ownerEmail = lodashGet(report, 'ownerEmail', ''); + const ownerEmail = report.ownerEmail || ''; const ownerIcon = { source: UserUtils.getAvatar(lodashGet(personalDetails, [ownerEmail, 'avatar']), ownerEmail), name: ownerEmail, From 270ce3b110c160f271749937b7856688664af2a9 Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 13 Jun 2023 13:46:02 -0500 Subject: [PATCH 079/100] fix: update PERSONAL_DETAILS_LIST when updating avatar --- src/libs/actions/PersonalDetails.js | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index b362436def5c..869d7da9b1cc 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -378,6 +378,21 @@ function updateAvatar(file) { }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + value: { + [personalDetails[currentUserEmail].accountID]: { + avatar: file.uri, + errorFields: { + avatar: null, + }, + pendingFields: { + avatar: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + }, + }, + }, ]; const successData = [ { @@ -391,6 +406,17 @@ function updateAvatar(file) { }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + value: { + [personalDetails[currentUserEmail].accountID]: { + pendingFields: { + avatar: null, + }, + }, + }, + }, ]; const failureData = [ { @@ -406,6 +432,18 @@ function updateAvatar(file) { }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + value: { + [personalDetails[currentUserEmail].accountID]: { + avatar: personalDetails[currentUserEmail].avatar, + pendingFields: { + avatar: null, + }, + }, + }, + }, ]; API.write('UpdateUserAvatar', {file}, {optimisticData, successData, failureData}); From 2283c67015d109ab154c271fad06111090992f98 Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 13 Jun 2023 14:04:30 -0500 Subject: [PATCH 080/100] fix: update avatar when deleting avatar --- src/libs/actions/PersonalDetails.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 869d7da9b1cc..5f2dadb15b8f 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -470,6 +470,15 @@ function deleteAvatar() { }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + value: { + [personalDetails[currentUserEmail].accountID]: { + avatar: defaultAvatar, + }, + }, + }, ], failureData: [ { @@ -481,6 +490,15 @@ function deleteAvatar() { }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + value: { + [personalDetails[currentUserEmail].accountID]: { + avatar: personalDetails[currentUserEmail].avatar, + }, + }, + }, ], }, ); From 159c8597db94474678f985ca6c6fa46657539716 Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Wed, 14 Jun 2023 01:10:15 +0530 Subject: [PATCH 081/100] using usePrevious hook instead of direct ref --- src/pages/home/report/ReportActionItemMessageEdit.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index a640ca011e1a..36ca2c5f1162 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -36,6 +36,7 @@ import * as ComposerActions from '../../../libs/actions/Composer'; import * as User from '../../../libs/actions/User'; import PressableWithFeedback from '../../../components/Pressable/PressableWithFeedback'; import Hoverable from '../../../components/Hoverable'; +import usePrevious from '../../../hooks/usePrevious' const propTypes = { /** All the data of the action */ @@ -96,12 +97,8 @@ function ReportActionItemMessageEdit(props) { const [hasExceededMaxCommentLength, setHasExceededMaxCommentLength] = useState(false); const textInputRef = useRef(null); - const isFocusedRef = useRef(false); + const wasPreviouslyFocused = usePrevious(isFocused); - useEffect(() => { - // required for keeping last state of isFocused variable - isFocusedRef.current = isFocused; - }, [isFocused]); useEffect(() => { // For mobile Safari, updating the selection prop on an unfocused input will cause it to automatically gain focus @@ -117,7 +114,7 @@ function ReportActionItemMessageEdit(props) { return () => { // Skip if this is not the focused message so the other edit composer stays focused - if (!isFocusedRef.current) { + if (wasPreviouslyFocused) { return; } @@ -125,6 +122,7 @@ function ReportActionItemMessageEdit(props) { // to prevent the main composer stays hidden until we swtich to another chat. ComposerActions.setShouldShowComposeInput(true); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); /** @@ -262,6 +260,7 @@ function ReportActionItemMessageEdit(props) { Date: Wed, 14 Jun 2023 01:15:27 +0530 Subject: [PATCH 082/100] prettier --- src/pages/home/report/ReportActionItemMessageEdit.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index 36ca2c5f1162..d1842c9fa752 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -36,7 +36,7 @@ import * as ComposerActions from '../../../libs/actions/Composer'; import * as User from '../../../libs/actions/User'; import PressableWithFeedback from '../../../components/Pressable/PressableWithFeedback'; import Hoverable from '../../../components/Hoverable'; -import usePrevious from '../../../hooks/usePrevious' +import usePrevious from '../../../hooks/usePrevious'; const propTypes = { /** All the data of the action */ @@ -99,7 +99,6 @@ function ReportActionItemMessageEdit(props) { const textInputRef = useRef(null); const wasPreviouslyFocused = usePrevious(isFocused); - useEffect(() => { // For mobile Safari, updating the selection prop on an unfocused input will cause it to automatically gain focus // and subsequent programmatic focus shifts (e.g., modal focus trap) to show the blue frame (:focus-visible style), @@ -122,7 +121,7 @@ function ReportActionItemMessageEdit(props) { // to prevent the main composer stays hidden until we swtich to another chat. ComposerActions.setShouldShowComposeInput(true); }; - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); /** From fe3cc67c689cdab36233bde940a19d2380a2821b Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Wed, 14 Jun 2023 02:02:48 +0530 Subject: [PATCH 083/100] added useKeyboardState hook --- src/hooks/useKeyboardState.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/hooks/useKeyboardState.js diff --git a/src/hooks/useKeyboardState.js b/src/hooks/useKeyboardState.js new file mode 100644 index 000000000000..cebb624ea09f --- /dev/null +++ b/src/hooks/useKeyboardState.js @@ -0,0 +1,23 @@ +import {useEffect, useState} from 'react'; +import {Keyboard} from 'react-native'; + +/** + * Hook for getting current state of keyboard + * whether or not the keyboard is open + * @returns {Object} + */ +export default function useKeyboardState() { + const [isKeyboardShown, setIsKeyboardShown] = useState(false); + + useEffect(() => { + const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => setIsKeyboardShown(true)); + return keyboardDidShowListener.remove; + }, []); + + useEffect(() => { + const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => setIsKeyboardShown(false)); + return keyboardDidHideListener.remove; + }, []); + + return {isKeyboardShown}; +} From fe6a826e17983ef8a1cc968e20d8d4adf9a75757 Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Wed, 14 Jun 2023 02:03:30 +0530 Subject: [PATCH 084/100] repalced usage of HOC with hooks --- .../report/ReportActionItemMessageEdit.js | 55 ++++++++----------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index d1842c9fa752..a93239fb358d 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -1,7 +1,6 @@ /* eslint-disable rulesdir/onyx-props-must-have-default */ import lodashGet from 'lodash/get'; import React, {useState, useRef, useMemo, useEffect, useCallback} from 'react'; -// eslint-disable-next-line no-restricted-imports import {InteractionManager, Keyboard, View} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; @@ -16,7 +15,6 @@ import * as Report from '../../../libs/actions/Report'; import * as ReportScrollManager from '../../../libs/ReportScrollManager'; import openReportActionComposeViewWhenClosingMessageEdit from '../../../libs/openReportActionComposeViewWhenClosingMessageEdit'; import ReportActionComposeFocusManager from '../../../libs/ReportActionComposeFocusManager'; -import compose from '../../../libs/compose'; import EmojiPickerButton from '../../../components/EmojiPicker/EmojiPickerButton'; import Icon from '../../../components/Icon'; import * as Expensicons from '../../../components/Icon/Expensicons'; @@ -27,9 +25,6 @@ import * as EmojiUtils from '../../../libs/EmojiUtils'; import reportPropTypes from '../../reportPropTypes'; import ExceededCommentLength from '../../../components/ExceededCommentLength'; import CONST from '../../../CONST'; -import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; -import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize'; -import withKeyboardState, {keyboardStatePropTypes} from '../../../components/withKeyboardState'; import refPropTypes from '../../../components/refPropTypes'; import * as ComposerUtils from '../../../libs/ComposerUtils'; import * as ComposerActions from '../../../libs/actions/Composer'; @@ -37,6 +32,9 @@ import * as User from '../../../libs/actions/User'; import PressableWithFeedback from '../../../components/Pressable/PressableWithFeedback'; import Hoverable from '../../../components/Hoverable'; import usePrevious from '../../../hooks/usePrevious'; +import useLocalize from '../../../hooks/useLocalize'; +import useKeyboardState from '../../../hooks/useKeyboardState'; +import useWindowDimensions from '../../../hooks/useWindowDimensions'; const propTypes = { /** All the data of the action */ @@ -63,10 +61,6 @@ const propTypes = { /** Stores user's preferred skin tone */ preferredSkinTone: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - - ...withLocalizePropTypes, - ...windowDimensionsPropTypes, - ...keyboardStatePropTypes, }; const defaultProps = { @@ -83,6 +77,10 @@ const emojiButtonID = 'emojiButton'; const messageEditInput = 'messageEditInput'; function ReportActionItemMessageEdit(props) { + const {translate} = useLocalize(); + const {isKeyboardShown} = useKeyboardState(); + const {isSmallScreenWidth} = useWindowDimensions(); + const [draft, setDraft] = useState(() => { if (props.draftMessage === props.action.message[0].html) { // We only convert the report action message to markdown if the draft message is unchanged. @@ -144,7 +142,7 @@ function ReportActionItemMessageEdit(props) { */ const updateDraft = useCallback( (newDraftInput) => { - const {text: newDraft = '', emojis = []} = EmojiUtils.replaceEmojis(newDraftInput, props.isSmallScreenWidth, props.preferredSkinTone); + const {text: newDraft = '', emojis = []} = EmojiUtils.replaceEmojis(newDraftInput, isSmallScreenWidth, props.preferredSkinTone); if (!_.isEmpty(emojis)) { User.updateFrequentlyUsedEmojis(EmojiUtils.getFrequentlyUsedEmojis(emojis)); @@ -171,7 +169,7 @@ function ReportActionItemMessageEdit(props) { debouncedSaveDraft(props.action.message[0].html); } }, - [props.action.message, debouncedSaveDraft, props.isSmallScreenWidth, props.preferredSkinTone], + [props.action.message, debouncedSaveDraft, isSmallScreenWidth, props.preferredSkinTone], ); /** @@ -235,7 +233,7 @@ function ReportActionItemMessageEdit(props) { */ const triggerSaveOrCancel = useCallback( (e) => { - if (!e || ComposerUtils.canSkipTriggerHotkeys(props.isSmallScreenWidth, props.isKeyboardShown)) { + if (!e || ComposerUtils.canSkipTriggerHotkeys(isSmallScreenWidth, isKeyboardShown)) { return; } if (e.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey && !e.shiftKey) { @@ -246,14 +244,14 @@ function ReportActionItemMessageEdit(props) { deleteDraft(); } }, - [deleteDraft, props.isKeyboardShown, props.isSmallScreenWidth, publishDraft], + [deleteDraft, isKeyboardShown, isSmallScreenWidth, publishDraft], ); return ( <> - + {(hovered) => ( { setIsFocused(true); @@ -333,14 +331,14 @@ function ReportActionItemMessageEdit(props) { - + @@ -364,16 +362,11 @@ function ReportActionItemMessageEdit(props) { ReportActionItemMessageEdit.propTypes = propTypes; ReportActionItemMessageEdit.defaultProps = defaultProps; ReportActionItemMessageEdit.displayName = 'ReportActionItemMessageEdit'; -export default compose( - withLocalize, - withWindowDimensions, - withKeyboardState, -)( - React.forwardRef((props, ref) => ( - - )), -); + +export default React.forwardRef((props, ref) => ( + +)); From 17469608ac5060d37c4c58a38cc924f65b90507c Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Wed, 14 Jun 2023 02:26:34 +0530 Subject: [PATCH 085/100] updated useKeyboardState hook to use KeyboardStateContext --- src/components/withKeyboardState.js | 2 +- src/hooks/useKeyboardState.js | 19 +++---------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/components/withKeyboardState.js b/src/components/withKeyboardState.js index c5a72f752003..667e8865a0e3 100755 --- a/src/components/withKeyboardState.js +++ b/src/components/withKeyboardState.js @@ -68,4 +68,4 @@ export default function withKeyboardState(WrappedComponent) { return WithKeyboardState; } -export {KeyboardStateProvider, keyboardStatePropTypes}; +export {KeyboardStateProvider, keyboardStatePropTypes, KeyboardStateContext}; diff --git a/src/hooks/useKeyboardState.js b/src/hooks/useKeyboardState.js index cebb624ea09f..064853d1814a 100644 --- a/src/hooks/useKeyboardState.js +++ b/src/hooks/useKeyboardState.js @@ -1,23 +1,10 @@ -import {useEffect, useState} from 'react'; -import {Keyboard} from 'react-native'; - +import {useContext} from 'react'; +import {KeyboardStateContext} from '../components/withKeyboardState'; /** * Hook for getting current state of keyboard * whether or not the keyboard is open * @returns {Object} */ export default function useKeyboardState() { - const [isKeyboardShown, setIsKeyboardShown] = useState(false); - - useEffect(() => { - const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => setIsKeyboardShown(true)); - return keyboardDidShowListener.remove; - }, []); - - useEffect(() => { - const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => setIsKeyboardShown(false)); - return keyboardDidHideListener.remove; - }, []); - - return {isKeyboardShown}; + return useContext(KeyboardStateContext); } From e41f473f29d506d6a20c473987285960827764d4 Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 13 Jun 2023 15:58:54 -0500 Subject: [PATCH 086/100] fix: remove avatar for NewDot --- src/libs/actions/PersonalDetails.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 5f2dadb15b8f..dd458a3a4f14 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -454,7 +454,7 @@ function updateAvatar(file) { */ function deleteAvatar() { // We want to use the old dot avatar here as this affects both platforms. - const defaultAvatar = UserUtils.getDefaultAvatarURL(currentUserEmail); + const defaultAvatar = UserUtils.getDefaultAvatarURL(currentUserEmail, true); API.write( 'DeleteUserAvatar', From b2d1fcbe4ef2bd282df284593e7c0a5a1729055e Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 13 Jun 2023 19:03:48 -0500 Subject: [PATCH 087/100] fix: remove todo comments --- src/pages/settings/Profile/Contacts/ContactMethodsPage.js | 2 -- src/pages/workspace/bills/WorkspaceBillsFirstSection.js | 2 -- src/pages/workspace/reimburse/WorkspaceReimburseView.js | 2 -- 3 files changed, 6 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ContactMethodsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodsPage.js index 7ea6e788211c..225612c3aaf7 100644 --- a/src/pages/settings/Profile/Contacts/ContactMethodsPage.js +++ b/src/pages/settings/Profile/Contacts/ContactMethodsPage.js @@ -118,8 +118,6 @@ const ContactMethodsPage = (props) => { /> - {/* Workaround to fix https://github.com/Expensify/App/issues/17368. - TODO: Remove `numberOfLines` once https://github.com/facebook/react-native/pull/35703 is merged and applied to our repo */} {props.translate('contacts.helpTextBeforeEmail')} { containerStyles={[styles.cardSection]} > - {/* Workaround to fix https://github.com/Expensify/App/issues/17368. - TODO: Remove `numberOfLines` once https://github.com/facebook/react-native/pull/35703 is merged and applied to our repo */} {props.translate('workspace.bills.askYourVendorsBeforeEmail')} {props.user.isFromPublicDomain ? ( diff --git a/src/pages/workspace/reimburse/WorkspaceReimburseView.js b/src/pages/workspace/reimburse/WorkspaceReimburseView.js index 0004a5d2e037..9005374826b3 100644 --- a/src/pages/workspace/reimburse/WorkspaceReimburseView.js +++ b/src/pages/workspace/reimburse/WorkspaceReimburseView.js @@ -152,8 +152,6 @@ class WorkspaceReimburseView extends React.Component { ]} > - {/* Workaround to fix https://github.com/Expensify/App/issues/17368. - TODO: Remove `numberOfLines` once https://github.com/facebook/react-native/pull/35703 is merged and applied to our repo */} {this.props.translate('workspace.reimburse.captureNoVBACopyBeforeEmail')} Date: Tue, 13 Jun 2023 21:42:35 -0500 Subject: [PATCH 088/100] fix: lint error --- src/pages/signin/Socials.js | 54 +++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/pages/signin/Socials.js b/src/pages/signin/Socials.js index 70d22cd19b64..f7a866d2023b 100644 --- a/src/pages/signin/Socials.js +++ b/src/pages/signin/Socials.js @@ -33,32 +33,34 @@ const socialsList = [ }, ]; -const Socials = () => ( - - {_.map(socialsList, (social) => ( - { - e.preventDefault(); - Link.openExternalLink(social.link); - }} - accessible={false} - style={[styles.mr1, styles.mt1]} - shouldUseAutoHitSlop={false} - > - {({hovered, pressed}) => ( - - )} - - ))} - -); +function Socials() { + return ( + + {_.map(socialsList, (social) => ( + { + e.preventDefault(); + Link.openExternalLink(social.link); + }} + accessible={false} + style={[styles.mr1, styles.mt1]} + shouldUseAutoHitSlop={false} + > + {({hovered, pressed}) => ( + + )} + + ))} + + ); +} Socials.displayName = 'Socials'; From 9676093ae03d1531ddbe500ed66c7ff56a6529a4 Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 13 Jun 2023 21:54:13 -0500 Subject: [PATCH 089/100] fix: accountID validation added --- src/libs/actions/PersonalDetails.js | 135 ++++++++++++++-------------- 1 file changed, 70 insertions(+), 65 deletions(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index dd458a3a4f14..9d68797ec5b0 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -378,73 +378,78 @@ function updateAvatar(file) { }, }, }, + ]; + + const successData = [ { onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS_LIST, + key: ONYXKEYS.PERSONAL_DETAILS, value: { - [personalDetails[currentUserEmail].accountID]: { - avatar: file.uri, - errorFields: { - avatar: null, - }, + [currentUserEmail]: { pendingFields: { - avatar: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + avatar: null, }, }, }, }, ]; - const successData = [ + const failureData = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS, value: { [currentUserEmail]: { + avatar: personalDetails[currentUserEmail].avatar, + avatarThumbnail: personalDetails[currentUserEmail].avatarThumbnail || personalDetails[currentUserEmail].avatar, pendingFields: { avatar: null, }, }, }, }, - { + ]; + + const accountID = lodashGet(personalDetails, [currentUserEmail, 'accountID'], ''); + if (accountID) { + optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [personalDetails[currentUserEmail].accountID]: { - pendingFields: { + [accountID]: { + avatar: file.uri, + errorFields: { avatar: null, }, + pendingFields: { + avatar: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, }, }, - }, - ]; - const failureData = [ - { + }); + successData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [currentUserEmail]: { - avatar: personalDetails[currentUserEmail].avatar, - avatarThumbnail: personalDetails[currentUserEmail].avatarThumbnail || personalDetails[currentUserEmail].avatar, + [accountID]: { pendingFields: { avatar: null, }, }, }, - }, - { + }); + failureData.push({ onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { - [personalDetails[currentUserEmail].accountID]: { + [accountID]: { avatar: personalDetails[currentUserEmail].avatar, pendingFields: { avatar: null, }, }, }, - }, - ]; + }); + } API.write('UpdateUserAvatar', {file}, {optimisticData, successData, failureData}); } @@ -456,52 +461,52 @@ function deleteAvatar() { // We want to use the old dot avatar here as this affects both platforms. const defaultAvatar = UserUtils.getDefaultAvatarURL(currentUserEmail, true); - API.write( - 'DeleteUserAvatar', - {}, + const optimisticData = [ { - optimisticData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, - value: { - [currentUserEmail]: { - avatar: defaultAvatar, - }, - }, + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS, + value: { + [currentUserEmail]: { + avatar: defaultAvatar, }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - value: { - [personalDetails[currentUserEmail].accountID]: { - avatar: defaultAvatar, - }, - }, + }, + }, + ]; + const failureData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS, + value: { + [currentUserEmail]: { + avatar: personalDetails[currentUserEmail].avatar, }, - ], - failureData: [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS, - value: { - [currentUserEmail]: { - avatar: personalDetails[currentUserEmail].avatar, - }, - }, + }, + }, + ]; + + const accountID = lodashGet(personalDetails, [currentUserEmail, 'accountID'], ''); + if (accountID) { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + value: { + [personalDetails[currentUserEmail].accountID]: { + avatar: defaultAvatar, }, - { - onyxMethod: Onyx.METHOD.MERGE, - key: ONYXKEYS.PERSONAL_DETAILS_LIST, - value: { - [personalDetails[currentUserEmail].accountID]: { - avatar: personalDetails[currentUserEmail].avatar, - }, - }, + }, + }); + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PERSONAL_DETAILS_LIST, + value: { + [personalDetails[currentUserEmail].accountID]: { + avatar: personalDetails[currentUserEmail].avatar, }, - ], - }, - ); + }, + }); + } + + API.write('DeleteUserAvatar', {}, {optimisticData, failureData}); } /** From 14e8999aafbf470f8a9d3091a56260b66c67b57a Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Tue, 13 Jun 2023 22:01:13 -0500 Subject: [PATCH 090/100] fix: lint error --- src/libs/actions/PersonalDetails.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 9d68797ec5b0..67365cf8add3 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -379,7 +379,6 @@ function updateAvatar(file) { }, }, ]; - const successData = [ { onyxMethod: Onyx.METHOD.MERGE, From b5c9058ab0d0b7f1700b69ae342df2b0ea003842 Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Wed, 14 Jun 2023 11:13:40 +0530 Subject: [PATCH 091/100] revert usage of usePrevious hook --- src/pages/home/report/ReportActionItemMessageEdit.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index a93239fb358d..c5b092487d70 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -1,4 +1,3 @@ -/* eslint-disable rulesdir/onyx-props-must-have-default */ import lodashGet from 'lodash/get'; import React, {useState, useRef, useMemo, useEffect, useCallback} from 'react'; import {InteractionManager, Keyboard, View} from 'react-native'; @@ -31,7 +30,6 @@ import * as ComposerActions from '../../../libs/actions/Composer'; import * as User from '../../../libs/actions/User'; import PressableWithFeedback from '../../../components/Pressable/PressableWithFeedback'; import Hoverable from '../../../components/Hoverable'; -import usePrevious from '../../../hooks/usePrevious'; import useLocalize from '../../../hooks/useLocalize'; import useKeyboardState from '../../../hooks/useKeyboardState'; import useWindowDimensions from '../../../hooks/useWindowDimensions'; @@ -95,7 +93,12 @@ function ReportActionItemMessageEdit(props) { const [hasExceededMaxCommentLength, setHasExceededMaxCommentLength] = useState(false); const textInputRef = useRef(null); - const wasPreviouslyFocused = usePrevious(isFocused); + const isFocusedRef = useRef(false); + + useEffect(() => { + // required for keeping last state of isFocused variable + isFocusedRef.current = isFocused; + }, [isFocused]); useEffect(() => { // For mobile Safari, updating the selection prop on an unfocused input will cause it to automatically gain focus @@ -111,7 +114,7 @@ function ReportActionItemMessageEdit(props) { return () => { // Skip if this is not the focused message so the other edit composer stays focused - if (wasPreviouslyFocused) { + if (!isFocusedRef.current) { return; } @@ -119,7 +122,6 @@ function ReportActionItemMessageEdit(props) { // to prevent the main composer stays hidden until we swtich to another chat. ComposerActions.setShouldShowComposeInput(true); }; - // eslint-disable-next-line react-hooks/exhaustive-deps }, []); /** From ddf049b3a63d67c0da2bdef8cae343b28c74792f Mon Sep 17 00:00:00 2001 From: Rahul kushwaha Date: Wed, 14 Jun 2023 15:22:41 +0530 Subject: [PATCH 092/100] added empty line after imports --- src/hooks/useKeyboardState.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hooks/useKeyboardState.js b/src/hooks/useKeyboardState.js index 064853d1814a..8b57fb60f2b6 100644 --- a/src/hooks/useKeyboardState.js +++ b/src/hooks/useKeyboardState.js @@ -1,5 +1,6 @@ import {useContext} from 'react'; import {KeyboardStateContext} from '../components/withKeyboardState'; + /** * Hook for getting current state of keyboard * whether or not the keyboard is open From ff9da2d4c8b360fa9dc59ba722d0cb98b3f97b6c Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Wed, 14 Jun 2023 15:48:13 +0500 Subject: [PATCH 093/100] feat: add comment for unlink fn --- src/libs/actions/Session/clearCache/index.native.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/actions/Session/clearCache/index.native.js b/src/libs/actions/Session/clearCache/index.native.js index d6064b8ae941..3bd647dbf8fb 100644 --- a/src/libs/actions/Session/clearCache/index.native.js +++ b/src/libs/actions/Session/clearCache/index.native.js @@ -1,6 +1,7 @@ import {CachesDirectoryPath, unlink} from 'react-native-fs'; function clearStorage() { + // `unlink` is used to delete the caches directory return unlink(CachesDirectoryPath); } From 1c3a20d35ba17bd3c1c538d0909b6a2c5573c9f3 Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Wed, 14 Jun 2023 12:54:06 -0500 Subject: [PATCH 094/100] fix: use of UserUtils.getAvatar --- src/components/UserDetailsTooltip/index.js | 3 ++- src/libs/actions/PersonalDetails.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/UserDetailsTooltip/index.js b/src/components/UserDetailsTooltip/index.js index 493b40a0a5e1..5dd2fa1c5785 100644 --- a/src/components/UserDetailsTooltip/index.js +++ b/src/components/UserDetailsTooltip/index.js @@ -9,6 +9,7 @@ import Tooltip from '../Tooltip'; import {propTypes, defaultProps} from './userDetailsTooltipPropTypes'; import styles from '../../styles/styles'; import ONYXKEYS from '../../ONYXKEYS'; +import * as UserUtils from '../../libs/UserUtils'; function UserDetailsTooltip(props) { const userDetails = lodashGet(props.personalDetailsList, props.accountID, props.fallbackUserDetails); @@ -18,7 +19,7 @@ function UserDetailsTooltip(props) { diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 67365cf8add3..9c7dde0c7aa4 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -458,7 +458,7 @@ function updateAvatar(file) { */ function deleteAvatar() { // We want to use the old dot avatar here as this affects both platforms. - const defaultAvatar = UserUtils.getDefaultAvatarURL(currentUserEmail, true); + const defaultAvatar = UserUtils.getDefaultAvatarURL(currentUserEmail); const optimisticData = [ { From 7a7d83c535dd5c1a42702d7fbe0c8aecc6f691d6 Mon Sep 17 00:00:00 2001 From: Oliver Wilks Date: Wed, 14 Jun 2023 19:31:03 +0100 Subject: [PATCH 095/100] Fix lint --- src/components/ReportActionItem/RenameAction.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/RenameAction.js b/src/components/ReportActionItem/RenameAction.js index fd58b8a6a8f4..5e81abd0917b 100644 --- a/src/components/ReportActionItem/RenameAction.js +++ b/src/components/ReportActionItem/RenameAction.js @@ -16,7 +16,7 @@ const propTypes = { ...withCurrentUserPersonalDetailsPropTypes, }; -const RenameAction = (props) => { +function RenameAction(props) { const currentUserAccountID = lodashGet(props.currentUserPersonalDetails, 'accountID', ''); const userDisplayName = lodashGet(props.action, ['person', 0, 'text']); const actorAccountID = lodashGet(props.action, 'actorAccountID', ''); From 0e289497c615dc481f5c902c8eeb8330d1cf7259 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Wed, 14 Jun 2023 19:57:30 +0000 Subject: [PATCH 096/100] Update version to 1.3.27-7 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 7c860d4ac340..e805ab54bcbc 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -106,8 +106,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001032706 - versionName "1.3.27-6" + versionCode 1001032707 + versionName "1.3.27-7" } splits { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index a73349d4f9d5..c04106c90e10 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -32,7 +32,7 @@ CFBundleVersion - 1.3.27.6 + 1.3.27.7 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 98de86749f65..4e0a68c90650 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.3.27.6 + 1.3.27.7 diff --git a/package-lock.json b/package-lock.json index 09324b86787c..1dbb78697d05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.27-6", + "version": "1.3.27-7", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.27-6", + "version": "1.3.27-7", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index a020c5129b09..ac4b3b9ce875 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.27-6", + "version": "1.3.27-7", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 22502ff9eba2c6d1ef1cfc201b01589197191305 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Wed, 14 Jun 2023 20:55:07 +0000 Subject: [PATCH 097/100] Update version to 1.3.28-0 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 4 ++-- ios/NewExpensifyTests/Info.plist | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index e805ab54bcbc..fcf7a0fa8f50 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -106,8 +106,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001032707 - versionName "1.3.27-7" + versionCode 1001032800 + versionName "1.3.28-0" } splits { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index c04106c90e10..1a6aeabfda52 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.3.27 + 1.3.28 CFBundleSignature ???? CFBundleURLTypes @@ -32,7 +32,7 @@ CFBundleVersion - 1.3.27.7 + 1.3.28.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 4e0a68c90650..3e98b2b72985 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.3.27 + 1.3.28 CFBundleSignature ???? CFBundleVersion - 1.3.27.7 + 1.3.28.0 diff --git a/package-lock.json b/package-lock.json index 1dbb78697d05..93683a708eb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.27-7", + "version": "1.3.28-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.27-7", + "version": "1.3.28-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index ac4b3b9ce875..ba98dcaaf249 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.27-7", + "version": "1.3.28-0", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From acdf6fbe6d9e49ecb683a8b1a825f4fee7e17e43 Mon Sep 17 00:00:00 2001 From: rory Date: Wed, 14 Jun 2023 14:04:30 -0700 Subject: [PATCH 098/100] Revert pod cache --- .github/workflows/platformDeploy.yml | 7 ------- .github/workflows/testBuild.yml | 7 ------- 2 files changed, 14 deletions(-) diff --git a/.github/workflows/platformDeploy.yml b/.github/workflows/platformDeploy.yml index bac7ab34920d..3884f88e4ff2 100644 --- a/.github/workflows/platformDeploy.yml +++ b/.github/workflows/platformDeploy.yml @@ -157,14 +157,7 @@ jobs: ruby-version: '2.7' bundler-cache: true - - uses: actions/cache@v3 - id: cache-pods - with: - path: ios/Pods - key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} - - name: Install cocoapods - if: steps.cache-pods.outputs.cache-hit != 'true' uses: nick-invision/retry@0711ba3d7808574133d713a0d92d2941be03a350 with: timeout_minutes: 10 diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml index b75ee2a402e4..cee2ad4c3b83 100644 --- a/.github/workflows/testBuild.yml +++ b/.github/workflows/testBuild.yml @@ -140,14 +140,7 @@ jobs: ruby-version: '2.7' bundler-cache: true - - uses: actions/cache@v3 - id: cache-pods - with: - path: ios/Pods - key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} - - name: Install cocoapods - if: steps.cache-pods.outputs.cache-hit != 'true' uses: nick-invision/retry@0711ba3d7808574133d713a0d92d2941be03a350 with: timeout_minutes: 10 From 0b393afbecbd65833335be1ea604873883befbac Mon Sep 17 00:00:00 2001 From: OSBotify Date: Wed, 14 Jun 2023 21:43:28 +0000 Subject: [PATCH 099/100] Update version to 1.3.28-1 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index fcf7a0fa8f50..a1293318f437 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -106,8 +106,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001032800 - versionName "1.3.28-0" + versionCode 1001032801 + versionName "1.3.28-1" } splits { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 1a6aeabfda52..7d6a513fe6b2 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -32,7 +32,7 @@ CFBundleVersion - 1.3.28.0 + 1.3.28.1 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 3e98b2b72985..cf678d5e8c27 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.3.28.0 + 1.3.28.1 diff --git a/package-lock.json b/package-lock.json index 93683a708eb7..ddf02da1424a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.28-0", + "version": "1.3.28-1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.28-0", + "version": "1.3.28-1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index ba98dcaaf249..4eefb3ad1f70 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.28-0", + "version": "1.3.28-1", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From f87b91a8d5b28b0fc6a24feda57b878bdfdfacbc Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 15 Jun 2023 00:30:35 +0000 Subject: [PATCH 100/100] Update version to 1.3.28-2 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index a1293318f437..1630538e4b8e 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -106,8 +106,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001032801 - versionName "1.3.28-1" + versionCode 1001032802 + versionName "1.3.28-2" } splits { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 7d6a513fe6b2..f3a960f1a98c 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -32,7 +32,7 @@ CFBundleVersion - 1.3.28.1 + 1.3.28.2 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index cf678d5e8c27..a2b4783ca4dd 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.3.28.1 + 1.3.28.2 diff --git a/package-lock.json b/package-lock.json index ddf02da1424a..7d460c18d812 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.28-1", + "version": "1.3.28-2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.28-1", + "version": "1.3.28-2", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 4eefb3ad1f70..a7b899d37204 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.28-1", + "version": "1.3.28-2", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",