From 5d8cf140999ba36befe81b6a4b2566749d5be8ed Mon Sep 17 00:00:00 2001 From: AHMED Date: Wed, 10 May 2023 09:23:48 +0300 Subject: [PATCH 1/6] fix/ copmpser hide on change screen size --- src/libs/toggleReportActionComposeView/index.js | 6 +----- src/pages/home/report/ReportActionCompose.js | 10 ++++++++-- src/pages/home/report/ReportFooter.js | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/libs/toggleReportActionComposeView/index.js b/src/libs/toggleReportActionComposeView/index.js index 70b580bfba44..3e266770b672 100644 --- a/src/libs/toggleReportActionComposeView/index.js +++ b/src/libs/toggleReportActionComposeView/index.js @@ -1,9 +1,5 @@ import * as Composer from '../actions/Composer'; -export default (shouldShowComposeInput, isSmallScreenWidth = true) => { - if (!isSmallScreenWidth) { - return; - } - +export default (shouldShowComposeInput) => { Composer.setShouldShowComposeInput(shouldShowComposeInput); }; diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index c21ccef92c9a..c0da5456a514 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -110,6 +110,8 @@ const propTypes = { expiresAt: PropTypes.string, }), + shouldShowComposeInput: PropTypes.bool, + /** Stores user's preferred skin tone */ preferredSkinTone: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), @@ -141,6 +143,7 @@ const defaultProps = { frequentlyUsedEmojis: [], isComposerFullSize: false, pendingAction: null, + shouldShowComposeInput: true, ...withCurrentUserPersonalDetailsDefaultProps, }; @@ -759,7 +762,7 @@ class ReportActionCompose extends React.Component { const isComposeDisabled = this.props.isDrawerOpen && this.props.isSmallScreenWidth; const isBlockedFromConcierge = ReportUtils.chatIncludesConcierge(this.props.report) && User.isBlockedFromConcierge(this.props.blockedFromConcierge); const inputPlaceholder = this.getInputPlaceholder(); - const shouldUseFocusedColor = !isBlockedFromConcierge && !this.props.disabled && (this.state.isFocused || this.state.isDraggingOver); + const shouldUseFocusedColor = !isBlockedFromConcierge && !this.props.disabled && (this.state.isFocused || this.state.isDraggingOver) && this.props.shouldShowComposeInput; const hasExceededMaxCommentLength = this.state.hasExceededMaxCommentLength; return ( @@ -902,7 +905,7 @@ class ReportActionCompose extends React.Component { disabled={this.props.disabled} > )} - {(!hideComposer && this.props.shouldShowComposeInput) && ( + {(!hideComposer && (this.props.shouldShowComposeInput || !this.props.isSmallScreenWidth)) && ( Date: Wed, 10 May 2023 14:47:33 +0300 Subject: [PATCH 2/6] replace lib with single file --- .../index.native.js => toggleReportActionComposeView.js} | 2 +- src/libs/toggleReportActionComposeView/index.js | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) rename src/libs/{toggleReportActionComposeView/index.native.js => toggleReportActionComposeView.js} (67%) delete mode 100644 src/libs/toggleReportActionComposeView/index.js diff --git a/src/libs/toggleReportActionComposeView/index.native.js b/src/libs/toggleReportActionComposeView.js similarity index 67% rename from src/libs/toggleReportActionComposeView/index.native.js rename to src/libs/toggleReportActionComposeView.js index 1ac971913e02..0748af625c26 100644 --- a/src/libs/toggleReportActionComposeView/index.native.js +++ b/src/libs/toggleReportActionComposeView.js @@ -1,3 +1,3 @@ -import * as Composer from '../actions/Composer'; +import * as Composer from './actions/Composer'; export default (shouldShowComposeInput) => Composer.setShouldShowComposeInput(shouldShowComposeInput); diff --git a/src/libs/toggleReportActionComposeView/index.js b/src/libs/toggleReportActionComposeView/index.js deleted file mode 100644 index 3e266770b672..000000000000 --- a/src/libs/toggleReportActionComposeView/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import * as Composer from '../actions/Composer'; - -export default (shouldShowComposeInput) => { - Composer.setShouldShowComposeInput(shouldShowComposeInput); -}; From ff6b92087c5fc4ad15dd8a4fd6dd7946908fdafa Mon Sep 17 00:00:00 2001 From: AHMED Date: Wed, 10 May 2023 14:57:38 +0300 Subject: [PATCH 3/6] update unfocused state on edit . --- src/pages/home/report/ReportActionCompose.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 0a701d8e79ac..1e40c5ddadb1 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -191,7 +191,7 @@ class ReportActionCompose extends React.Component { this.willBlurTextInputOnTapOutside = willBlurTextInputOnTapOutside(); this.state = { - isFocused: this.willBlurTextInputOnTapOutside && !this.props.modal.isVisible && !this.props.modal.willAlertModalBecomeVisible, + isFocused: this.willBlurTextInputOnTapOutside && !this.props.modal.isVisible && !this.props.modal.willAlertModalBecomeVisible && this.props.shouldShowComposeInput, isFullComposerAvailable: props.isComposerFullSize, textInputShouldClear: false, isCommentEmpty: props.comment.length === 0, @@ -772,7 +772,7 @@ class ReportActionCompose extends React.Component { const isComposeDisabled = this.props.isDrawerOpen && this.props.isSmallScreenWidth; const isBlockedFromConcierge = ReportUtils.chatIncludesConcierge(this.props.report) && User.isBlockedFromConcierge(this.props.blockedFromConcierge); const inputPlaceholder = this.getInputPlaceholder(); - const shouldUseFocusedColor = !isBlockedFromConcierge && !this.props.disabled && (this.state.isFocused || this.state.isDraggingOver) && this.props.shouldShowComposeInput; + const shouldUseFocusedColor = !isBlockedFromConcierge && !this.props.disabled && (this.state.isFocused || this.state.isDraggingOver); const hasExceededMaxCommentLength = this.state.hasExceededMaxCommentLength; return ( From 109d6b280024a4547577813b0afa0b57ed5c3f0e Mon Sep 17 00:00:00 2001 From: AHMED Date: Wed, 10 May 2023 15:01:17 +0300 Subject: [PATCH 4/6] add comment to shouldShowComposeInput --- src/pages/home/report/ReportActionCompose.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 1e40c5ddadb1..9188d1a081e1 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -104,7 +104,8 @@ const propTypes = { // The date that the user will be unblocked expiresAt: PropTypes.string, }), - + + /** Whether the composer input should be shown */ shouldShowComposeInput: PropTypes.bool, /** Stores user's preferred skin tone */ From 391aa8de208d62219b425b9d22d65d57d2dd054e Mon Sep 17 00:00:00 2001 From: AHMED Date: Thu, 11 May 2023 09:40:50 +0300 Subject: [PATCH 5/6] remove toggleReportActionComposeView --- .../index.js | 6 +++--- .../index.native.js | 6 +++--- src/libs/toggleReportActionComposeView.js | 3 --- src/pages/home/ReportScreen.js | 6 +++--- src/pages/home/report/ReportActionCompose.js | 6 +++--- src/pages/home/report/ReportActionItemMessageEdit.js | 10 +++++----- 6 files changed, 17 insertions(+), 20 deletions(-) delete mode 100644 src/libs/toggleReportActionComposeView.js diff --git a/src/libs/openReportActionComposeViewWhenClosingMessageEdit/index.js b/src/libs/openReportActionComposeViewWhenClosingMessageEdit/index.js index 1174b409c4d6..4f3e8c5de2c8 100644 --- a/src/libs/openReportActionComposeViewWhenClosingMessageEdit/index.js +++ b/src/libs/openReportActionComposeViewWhenClosingMessageEdit/index.js @@ -1,5 +1,5 @@ -import toggleReportActionComposeView from '../toggleReportActionComposeView'; +import * as Composer from '../actions/Composer'; -export default (isSmallScreenWidth = true) => { - toggleReportActionComposeView(true, isSmallScreenWidth); +export default () => { + Composer.setShouldShowComposeInput(true); }; diff --git a/src/libs/openReportActionComposeViewWhenClosingMessageEdit/index.native.js b/src/libs/openReportActionComposeViewWhenClosingMessageEdit/index.native.js index 3bbfb73d30fc..488769741715 100644 --- a/src/libs/openReportActionComposeViewWhenClosingMessageEdit/index.native.js +++ b/src/libs/openReportActionComposeViewWhenClosingMessageEdit/index.native.js @@ -1,9 +1,9 @@ import {Keyboard} from 'react-native'; -import toggleReportActionComposeView from '../toggleReportActionComposeView'; +import * as Composer from '../actions/Composer'; -export default (isSmallScreenWidth = true) => { +export default () => { const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => { - toggleReportActionComposeView(true, isSmallScreenWidth); + Composer.setShouldShowComposeInput(true); keyboardDidHideListener.remove(); }); }; diff --git a/src/libs/toggleReportActionComposeView.js b/src/libs/toggleReportActionComposeView.js deleted file mode 100644 index 0748af625c26..000000000000 --- a/src/libs/toggleReportActionComposeView.js +++ /dev/null @@ -1,3 +0,0 @@ -import * as Composer from './actions/Composer'; - -export default (shouldShowComposeInput) => Composer.setShouldShowComposeInput(shouldShowComposeInput); diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 7eb837346b12..2f0d48996d42 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -19,7 +19,6 @@ import ReportActionsView from './report/ReportActionsView'; import CONST from '../../CONST'; import ReportActionsSkeletonView from '../../components/ReportActionsSkeletonView'; import reportActionPropTypes from './report/reportActionPropTypes'; -import toggleReportActionComposeView from '../../libs/toggleReportActionComposeView'; import {withNetwork} from '../../components/OnyxProvider'; import compose from '../../libs/compose'; import Visibility from '../../libs/Visibility'; @@ -41,6 +40,7 @@ import EmojiPicker from '../../components/EmojiPicker/EmojiPicker'; import * as EmojiPickerAction from '../../libs/actions/EmojiPickerAction'; import TaskHeaderView from './TaskHeaderView'; import MoneyRequestHeader from '../../components/MoneyRequestHeader'; +import * as ComposerActions from '../../libs/actions/Composer'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -147,7 +147,7 @@ class ReportScreen extends React.Component { }); this.fetchReportIfNeeded(); - toggleReportActionComposeView(true); + ComposerActions.setShouldShowComposeInput(true); Navigation.setIsReportScreenIsReady(); } @@ -163,7 +163,7 @@ class ReportScreen extends React.Component { } this.fetchReportIfNeeded(); - toggleReportActionComposeView(true); + ComposerActions.setShouldShowComposeInput(true); } componentWillUnmount() { diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 9188d1a081e1..69c6fc0e7fda 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -34,7 +34,6 @@ import * as User from '../../../libs/actions/User'; import Tooltip from '../../../components/Tooltip'; import EmojiPickerButton from '../../../components/EmojiPicker/EmojiPickerButton'; import * as DeviceCapabilities from '../../../libs/DeviceCapabilities'; -import toggleReportActionComposeView from '../../../libs/toggleReportActionComposeView'; import OfflineIndicator from '../../../components/OfflineIndicator'; import ExceededCommentLength from '../../../components/ExceededCommentLength'; import withNavigationFocus from '../../../components/withNavigationFocus'; @@ -49,6 +48,7 @@ import ArrowKeyFocusManager from '../../../components/ArrowKeyFocusManager'; import OfflineWithFeedback from '../../../components/OfflineWithFeedback'; import KeyboardShortcut from '../../../libs/KeyboardShortcut'; import * as ComposerUtils from '../../../libs/ComposerUtils'; +import * as ComposerActions from '../../../libs/actions/Composer'; import * as Welcome from '../../../libs/actions/Welcome'; import Permissions from '../../../libs/Permissions'; import * as TaskUtils from '../../../libs/actions/Task'; @@ -104,7 +104,7 @@ const propTypes = { // The date that the user will be unblocked expiresAt: PropTypes.string, }), - + /** Whether the composer input should be shown */ shouldShowComposeInput: PropTypes.bool, @@ -260,7 +260,7 @@ class ReportActionCompose extends React.Component { componentDidUpdate(prevProps) { const sidebarOpened = !prevProps.isDrawerOpen && this.props.isDrawerOpen; if (sidebarOpened) { - toggleReportActionComposeView(true); + ComposerActions.setShouldShowComposeInput(true); } // We want to focus or refocus the input when a modal has been closed and the underlying screen is focused. diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index 4d44cde04034..ad76d776b110 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -13,7 +13,6 @@ import * as StyleUtils from '../../../styles/StyleUtils'; import Composer from '../../../components/Composer'; import * as Report from '../../../libs/actions/Report'; import * as ReportScrollManager from '../../../libs/ReportScrollManager'; -import toggleReportActionComposeView from '../../../libs/toggleReportActionComposeView'; import openReportActionComposeViewWhenClosingMessageEdit from '../../../libs/openReportActionComposeViewWhenClosingMessageEdit'; import ReportActionComposeFocusManager from '../../../libs/ReportActionComposeFocusManager'; import compose from '../../../libs/compose'; @@ -32,6 +31,7 @@ import withWindowDimensions, {windowDimensionsPropTypes} from '../../../componen import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize'; import withKeyboardState, {keyboardStatePropTypes} from '../../../components/withKeyboardState'; import * as ComposerUtils from '../../../libs/ComposerUtils'; +import * as ComposerActions from '../../../libs/actions/Composer'; const propTypes = { /** All the data of the action */ @@ -116,7 +116,7 @@ class ReportActionItemMessageEdit extends React.Component { // 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. - toggleReportActionComposeView(true, this.props.isSmallScreenWidth); + ComposerActions.setShouldShowComposeInput(true); } /** @@ -173,7 +173,7 @@ class ReportActionItemMessageEdit extends React.Component { deleteDraft() { this.debouncedSaveDraft.cancel(); Report.saveReportActionDraft(this.props.reportID, this.props.action.reportActionID, ''); - toggleReportActionComposeView(true, this.props.isSmallScreenWidth); + ComposerActions.setShouldShowComposeInput(true); ReportActionComposeFocusManager.focus(); // Scroll to the last comment after editing to make sure the whole comment is clearly visible in the report. @@ -304,7 +304,7 @@ class ReportActionItemMessageEdit extends React.Component { onFocus={() => { this.setState({isFocused: true}); ReportScrollManager.scrollToIndex({animated: true, index: this.props.index}, true); - toggleReportActionComposeView(false, this.props.isSmallScreenWidth); + ComposerActions.setShouldShowComposeInput(false); }} onBlur={(event) => { this.setState({isFocused: false}); @@ -318,7 +318,7 @@ class ReportActionItemMessageEdit extends React.Component { if (this.messageEditInput === relatedTargetId) { return; } - openReportActionComposeViewWhenClosingMessageEdit(this.props.isSmallScreenWidth); + openReportActionComposeViewWhenClosingMessageEdit(); }} selection={this.state.selection} onSelectionChange={this.onSelectionChange} From e088b77d25f5c4994e3dacd06d233c82e69222a6 Mon Sep 17 00:00:00 2001 From: AHMED Date: Thu, 11 May 2023 09:47:57 +0300 Subject: [PATCH 6/6] Merge branch 'main' into fix/Composer-not-displayed --- .prettierignore | 2 + android/app/build.gradle | 4 +- ios/NewExpensify/Info.plist | 4 +- ios/NewExpensifyTests/Info.plist | 4 +- package-lock.json | 16 +- package.json | 4 +- src/CONST.js | 5 + src/ONYXKEYS.js | 4 + src/ROUTES.js | 1 - src/components/Checkbox.js | 5 + src/components/LHNOptionsList/OptionRowLHN.js | 2 +- src/components/MentionSuggestions.js | 111 ++++++++++ src/components/OptionsList/BaseOptionsList.js | 63 +++--- .../OptionsList/optionsListPropTypes.js | 4 + ...etonView.js => OptionsListSkeletonView.js} | 8 +- .../OptionsSelector/BaseOptionsSelector.js | 6 +- .../Reactions/ReactionTooltipContent.js | 20 +- .../Reactions/ReportActionItemReactions.js | 3 +- src/components/ReportActionItem/IOUPreview.js | 59 +++++- .../{IOUAction.js => MoneyRequestAction.js} | 10 +- .../ReportActionItem/TaskPreview.js | 95 +++++++++ src/components/TextInput/BaseTextInput.js | 7 +- .../withCurrentUserPersonalDetails.js | 9 +- src/languages/en.js | 5 + src/languages/es.js | 5 + src/libs/GetStyledTextArray.js | 2 +- src/libs/OptionsListUtils.js | 19 +- src/libs/PersonalDetailsUtils.js | 7 +- src/libs/ReportActionsUtils.js | 5 + src/libs/ReportUtils.js | 33 ++- src/libs/SidebarUtils.js | 11 +- .../Device/getDeviceInfo/getBaseInfo.js | 8 + .../getDeviceInfo/getOSAndName/index.js | 3 + .../getOSAndName/index.native.js | 11 + .../Device/getDeviceInfo/index.android.js | 10 + .../Device/getDeviceInfo/index.desktop.js | 10 + .../actions/Device/getDeviceInfo/index.ios.js | 10 + .../actions/Device/getDeviceInfo/index.js | 23 ++ src/libs/actions/Device/index.js | 3 +- src/libs/actions/Report.js | 5 - src/libs/actions/Session/index.js | 20 +- src/libs/actions/Task.js | 56 +++-- src/libs/actions/User.js | 108 ++++++++++ src/pages/NewChatPage.js | 54 +++-- src/pages/SearchPage.js | 18 +- src/pages/home/HeaderView.js | 24 ++- .../report/ContextMenu/ContextMenuActions.js | 2 + src/pages/home/report/ReportActionCompose.js | 197 +++++++++++++++--- src/pages/home/report/ReportActionItem.js | 14 +- .../home/report/ReportActionItemCreated.js | 2 +- src/pages/home/report/ReportFooter.js | 4 +- .../home/report/reportActionPropTypes.js | 1 - src/pages/home/sidebar/SidebarLinks.js | 4 +- .../MoneyRequestParticipantsSelector.js | 17 ++ .../MoneyRequestParticipantsSplitSelector.js | 17 ++ src/pages/personalDetailsPropType.js | 4 +- .../Contacts/ContactMethodDetailsPage.js | 84 +++++++- .../workspace/WorkspaceInviteMessagePage.js | 12 +- src/pages/workspace/WorkspaceInvitePage.js | 43 ++-- src/pages/workspace/WorkspaceMembersPage.js | 10 +- src/styles/styles.js | 16 ++ 61 files changed, 1110 insertions(+), 213 deletions(-) create mode 100644 src/components/MentionSuggestions.js rename src/components/{LHNSkeletonView.js => OptionsListSkeletonView.js} (94%) rename src/components/ReportActionItem/{IOUAction.js => MoneyRequestAction.js} (96%) create mode 100644 src/components/ReportActionItem/TaskPreview.js create mode 100644 src/libs/actions/Device/getDeviceInfo/getBaseInfo.js create mode 100644 src/libs/actions/Device/getDeviceInfo/getOSAndName/index.js create mode 100644 src/libs/actions/Device/getDeviceInfo/getOSAndName/index.native.js create mode 100644 src/libs/actions/Device/getDeviceInfo/index.android.js create mode 100644 src/libs/actions/Device/getDeviceInfo/index.desktop.js create mode 100644 src/libs/actions/Device/getDeviceInfo/index.ios.js create mode 100644 src/libs/actions/Device/getDeviceInfo/index.js diff --git a/.prettierignore b/.prettierignore index c7a5913c6ef8..5cad6e04b900 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,4 @@ # The GH actions don't seem to compile and verify themselves well when Prettier is applied to them .github/actions/javascript/**/index.js +desktop/dist/**/*.js +dist/**/*.js diff --git a/android/app/build.gradle b/android/app/build.gradle index eef2dc928648..015f02d114f3 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 1001031201 - versionName "1.3.12-1" + versionCode 1001031300 + versionName "1.3.13-0" } splits { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 8ede6f57a788..f6ab2448f034 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.3.12 + 1.3.13 CFBundleSignature ???? CFBundleURLTypes @@ -30,7 +30,7 @@ CFBundleVersion - 1.3.12.1 + 1.3.13.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 87c4b3a720fb..4572d4f22020 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.3.12 + 1.3.13 CFBundleSignature ???? CFBundleVersion - 1.3.12.1 + 1.3.13.0 diff --git a/package-lock.json b/package-lock.json index cd81a5a4b510..8520c058c17d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.12-1", + "version": "1.3.13-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.12-1", + "version": "1.3.13-0", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -40,7 +40,7 @@ "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#d9c8b08ca67363e4442291ae283326d25f445cc5", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#b29d8528cd9be19a131ef77f9edfeb652d2af646", "fbjs": "^3.0.2", "html-entities": "^1.3.1", "htmlparser2": "^7.2.0", @@ -23463,8 +23463,8 @@ }, "node_modules/expensify-common": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#d9c8b08ca67363e4442291ae283326d25f445cc5", - "integrity": "sha512-Gg9iry9Wa5+ot73mZ6c8GetDcfqfW20e70mA1JyxKsmZ5frUmFWZ3dbQ8GgHZeaAzEKMVvQfGKDM9QfIQaz0FA==", + "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#b29d8528cd9be19a131ef77f9edfeb652d2af646", + "integrity": "sha512-IpZFu0qyDu8i7rgAki+mWHVS/bbrAGNJZnGTN/Oz1tY+AxL+9H8SwCW6n3r8Z7mzMsolirV6jj2gL6y4NgeIIQ==", "license": "MIT", "dependencies": { "classnames": "2.3.1", @@ -57100,9 +57100,9 @@ } }, "expensify-common": { - "version": "git+ssh://git@github.com/Expensify/expensify-common.git#d9c8b08ca67363e4442291ae283326d25f445cc5", - "integrity": "sha512-Gg9iry9Wa5+ot73mZ6c8GetDcfqfW20e70mA1JyxKsmZ5frUmFWZ3dbQ8GgHZeaAzEKMVvQfGKDM9QfIQaz0FA==", - "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#d9c8b08ca67363e4442291ae283326d25f445cc5", + "version": "git+ssh://git@github.com/Expensify/expensify-common.git#b29d8528cd9be19a131ef77f9edfeb652d2af646", + "integrity": "sha512-IpZFu0qyDu8i7rgAki+mWHVS/bbrAGNJZnGTN/Oz1tY+AxL+9H8SwCW6n3r8Z7mzMsolirV6jj2gL6y4NgeIIQ==", + "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#b29d8528cd9be19a131ef77f9edfeb652d2af646", "requires": { "classnames": "2.3.1", "clipboard": "2.0.4", diff --git a/package.json b/package.json index a6a3505634a0..0328a8450192 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.12-1", + "version": "1.3.13-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.", @@ -75,7 +75,7 @@ "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#d9c8b08ca67363e4442291ae283326d25f445cc5", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#b29d8528cd9be19a131ef77f9edfeb652d2af646", "fbjs": "^3.0.2", "html-entities": "^1.3.1", "htmlparser2": "^7.2.0", diff --git a/src/CONST.js b/src/CONST.js index b53e2d42b5a3..a501dc100f9d 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -1011,12 +1011,17 @@ const CONST = { CODE_2FA: /^\d{6}$/, ATTACHMENT_ID: /chat-attachments\/(\d+)/, HAS_COLON_ONLY_AT_THE_BEGINNING: /^:[^:]+$/, + HAS_AT_MOST_TWO_AT_SIGNS: /^@[^@]*@?[^@]*$/, // eslint-disable-next-line no-misleading-character-class NEW_LINE_OR_WHITE_SPACE_OR_EMOJI: /[\n\s\p{Extended_Pictographic}\u200d\u{1f1e6}-\u{1f1ff}\u{1f3fb}-\u{1f3ff}\u{e0020}-\u{e007f}\u20E3\uFE0F]|[#*0-9]\uFE0F?\u20E3/gu, // Define the regular expression pattern to match a string starting with a colon and ending with a space or newline character EMOJI_REPLACER: /^:[^\n\r]+?(?=$|\s)/, + + // Define the regular expression pattern to match a string starting with an at sign and ending with a space or newline character + MENTION_REPLACER: /^@[^\n\r]*?(?=$|\s)/, + MERGED_ACCOUNT_PREFIX: /^(MERGED_\d+@)/, }, diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index ff2c32f3d94d..f93e80328019 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -119,6 +119,7 @@ export default { REPORT_DRAFT_COMMENT_NUMBER_OF_LINES: 'reportDraftCommentNumberOfLines_', REPORT_IS_COMPOSER_FULL_SIZE: 'reportIsComposerFullSize_', REPORT_USER_IS_TYPING: 'reportUserIsTyping_', + SECURITY_GROUP: 'securityGroup_', TRANSACTION: 'transactions_', }, @@ -212,4 +213,7 @@ export default { // Whether the auth token is valid IS_TOKEN_VALID: 'isTokenValid', + + // A map of the user's security group IDs they belong to in specific domains + MY_DOMAIN_SECURITY_GROUPS: 'myDomainSecurityGroups', }; diff --git a/src/ROUTES.js b/src/ROUTES.js index 584d01088bc3..d0e16820772c 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -102,7 +102,6 @@ export default { NEW_TASK_DETAILS: `${NEW_TASK}/details`, NEW_TASK_TITLE: `${NEW_TASK}/title`, NEW_TASK_DESCRIPTION: `${NEW_TASK}/description`, - getTaskDetailsRoute: (taskID) => `task/details/${taskID}`, SEARCH: 'search', SET_PASSWORD_WITH_VALIDATE_CODE: 'setpassword/:accountID/:validateCode', DETAILS: 'details', diff --git a/src/components/Checkbox.js b/src/components/Checkbox.js index 19d46a2470ae..9e4f5da57dcf 100644 --- a/src/components/Checkbox.js +++ b/src/components/Checkbox.js @@ -26,6 +26,9 @@ const propTypes = { /** Additional styles to add to checkbox button */ style: stylePropTypes, + /** Additional styles to add to checkbox container */ + containerStyle: stylePropTypes, + /** Callback that is called when mousedown is triggered. */ onMouseDown: PropTypes.func, @@ -38,6 +41,7 @@ const defaultProps = { hasError: false, disabled: false, style: [], + containerStyle: [], forwardedRef: undefined, children: null, onMouseDown: undefined, @@ -112,6 +116,7 @@ class Checkbox extends React.Component { { tooltipEnabled numberOfLines={1} textStyles={displayNameStyle} - shouldUseFullTitle={optionItem.isChatRoom || optionItem.isPolicyExpenseChat} + shouldUseFullTitle={optionItem.isChatRoom || optionItem.isPolicyExpenseChat || optionItem.isTaskReport} /> {optionItem.isChatRoom && ( item.alternateText; + +const MentionSuggestions = (props) => { + /** + * Render a suggestion menu item component. + * @param {Object} item + * @returns {JSX.Element} + */ + const renderSuggestionMenuItem = (item) => { + const displayedText = _.uniq([item.text, item.alternateText]).join(' - '); + const styledTextArray = getStyledTextArray(displayedText, props.prefix); + + return ( + + + + {_.map(styledTextArray, ({text, isColored}, i) => ( + + {text} + + ))} + + + ); + }; + + return ( + + ); +}; + +MentionSuggestions.propTypes = propTypes; +MentionSuggestions.defaultProps = defaultProps; +MentionSuggestions.displayName = 'MentionSuggestions'; + +export default MentionSuggestions; diff --git a/src/components/OptionsList/BaseOptionsList.js b/src/components/OptionsList/BaseOptionsList.js index 14b0ccc5a3b6..df14af5234bd 100644 --- a/src/components/OptionsList/BaseOptionsList.js +++ b/src/components/OptionsList/BaseOptionsList.js @@ -8,6 +8,7 @@ import OptionRow from '../OptionRow'; import SectionList from '../SectionList'; import Text from '../Text'; import {propTypes as optionsListPropTypes, defaultProps as optionsListDefaultProps} from './optionsListPropTypes'; +import OptionsListSkeletonView from '../OptionsListSkeletonView'; const propTypes = { /** Determines whether the keyboard gets dismissed in response to a drag */ @@ -49,7 +50,7 @@ class BaseOptionsList extends Component { nextProps.focusedIndex !== this.props.focusedIndex || nextProps.selectedOptions.length !== this.props.selectedOptions.length || nextProps.headerMessage !== this.props.headerMessage || - !_.isEqual(nextProps.sections, this.props.sections) || + nextProps.isLoading !== this.props.isLoading || !_.isEqual(nextProps.sections, this.props.sections) ); } @@ -206,33 +207,39 @@ class BaseOptionsList extends Component { render() { return ( - {this.props.headerMessage ? ( - - {this.props.headerMessage} - - ) : null} - + {this.props.isLoading ? ( + + ) : ( + <> + {this.props.headerMessage ? ( + + {this.props.headerMessage} + + ) : null} + + + )} ); } diff --git a/src/components/OptionsList/optionsListPropTypes.js b/src/components/OptionsList/optionsListPropTypes.js index 15cb2b4b8a60..915d84e058c3 100644 --- a/src/components/OptionsList/optionsListPropTypes.js +++ b/src/components/OptionsList/optionsListPropTypes.js @@ -64,6 +64,9 @@ const propTypes = { /** Whether to disable the interactivity of the list's option row(s) */ isDisabled: PropTypes.bool, + /** Whether the options list skeleton loading view should be displayed */ + isLoading: PropTypes.bool, + /** Callback to execute when the SectionList lays out */ onLayout: PropTypes.func, @@ -90,6 +93,7 @@ const defaultProps = { innerRef: null, showTitleTooltip: false, isDisabled: false, + isLoading: false, onLayout: undefined, shouldHaveOptionSeparator: false, shouldDisableRowInnerPadding: false, diff --git a/src/components/LHNSkeletonView.js b/src/components/OptionsListSkeletonView.js similarity index 94% rename from src/components/LHNSkeletonView.js rename to src/components/OptionsListSkeletonView.js index 98f988f63066..02aca958eddd 100644 --- a/src/components/LHNSkeletonView.js +++ b/src/components/OptionsListSkeletonView.js @@ -16,7 +16,7 @@ const defaultTypes = { shouldAnimate: true, }; -class LHNSkeletonView extends React.Component { +class OptionsListSkeletonView extends React.Component { constructor(props) { super(props); this.state = { @@ -105,7 +105,7 @@ class LHNSkeletonView extends React.Component { } } -LHNSkeletonView.propTypes = propTypes; -LHNSkeletonView.defaultProps = defaultTypes; +OptionsListSkeletonView.propTypes = propTypes; +OptionsListSkeletonView.defaultProps = defaultTypes; -export default LHNSkeletonView; +export default OptionsListSkeletonView; diff --git a/src/components/OptionsSelector/BaseOptionsSelector.js b/src/components/OptionsSelector/BaseOptionsSelector.js index c1cf0799c391..21af8d1762db 100755 --- a/src/components/OptionsSelector/BaseOptionsSelector.js +++ b/src/components/OptionsSelector/BaseOptionsSelector.js @@ -12,7 +12,6 @@ import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import TextInput from '../TextInput'; import ArrowKeyFocusManager from '../ArrowKeyFocusManager'; import KeyboardShortcut from '../../libs/KeyboardShortcut'; -import FullScreenLoadingIndicator from '../FullscreenLoadingIndicator'; import {propTypes as optionsSelectorPropTypes, defaultProps as optionsSelectorDefaultProps} from './optionsSelectorPropTypes'; import setSelection from '../../libs/setSelection'; @@ -289,7 +288,7 @@ class BaseOptionsSelector extends Component { blurOnSubmit={Boolean(this.state.allOptions.length)} /> ); - const optionsList = this.props.shouldShowOptions ? ( + const optionsList = ( (this.list = el)} optionHoveredStyle={this.props.optionHoveredStyle} @@ -314,9 +313,8 @@ class BaseOptionsSelector extends Component { } }} contentContainerStyles={shouldShowFooter ? undefined : [this.props.safeAreaPaddingBottomStyle]} + isLoading={!this.props.shouldShowOptions} /> - ) : ( - ); return ( { - const users = PersonalDetailsUtils.getPersonalDetailsByIDs(props.accountIDs, true); + const users = useMemo( + () => PersonalDetailsUtils.getPersonalDetailsByIDs(props.accountIDs, props.currentUserPersonalDetails.accountID, true), + [props.currentUserPersonalDetails.accountID, props.accountIDs], + ); const namesString = _.filter( _.map(users, (user) => user && user.displayName), (n) => n, ).join(', '); - return ( @@ -57,6 +61,6 @@ const ReactionTooltipContent = (props) => { }; ReactionTooltipContent.propTypes = propTypes; -ReactionTooltipContent.defaultProps = withCurrentUserPersonalDetails; +ReactionTooltipContent.defaultProps = defaultProps; ReactionTooltipContent.displayName = 'ReactionTooltipContent'; -export default React.memo(compose(withPersonalDetails(), withLocalize)(ReactionTooltipContent)); +export default React.memo(withLocalize(ReactionTooltipContent)); diff --git a/src/components/Reactions/ReportActionItemReactions.js b/src/components/Reactions/ReportActionItemReactions.js index 5cb2d5d6add1..314f00c68280 100644 --- a/src/components/Reactions/ReportActionItemReactions.js +++ b/src/components/Reactions/ReportActionItemReactions.js @@ -84,7 +84,7 @@ const ReportActionItemReactions = (props) => { props.toggleReaction(emoji); }; const onReactionListOpen = (event) => { - const users = PersonalDetailsUtils.getPersonalDetailsByIDs(reactionUsers); + const users = PersonalDetailsUtils.getPersonalDetailsByIDs(reactionUsers, props.currentUserPersonalDetails.accountID); ReactionList.showReactionList(event, popoverReactionListAnchor.current, users, reaction.emoji, emojiCodes, reactionCount, hasUserReacted); }; @@ -95,6 +95,7 @@ const ReportActionItemReactions = (props) => { emojiName={reaction.emoji} emojiCodes={emojiCodes} accountIDs={reactionUsers} + currentUserPersonalDetails={props.currentUserPersonalDetails} /> )} renderTooltipContentKey={[...reactionUsers, ...emojiCodes]} diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index 202689085d97..758c708e4d91 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -26,6 +26,8 @@ import {showContextMenuForReport} from '../ShowContextMenuContext'; import * as OptionsListUtils from '../../libs/OptionsListUtils'; import Button from '../Button'; import * as CurrencyUtils from '../../libs/CurrencyUtils'; +import * as StyleUtils from '../../styles/StyleUtils'; +import getButtonState from '../../libs/getButtonState'; const propTypes = { /** Additional logic for displaying the pay button */ @@ -142,7 +144,7 @@ const IOUPreview = (props) => { const managerEmail = props.iouReport.managerEmail || ''; const ownerEmail = props.iouReport.ownerEmail || ''; - // When displaying within a IOUDetailsModal we cannot guarentee that participants are included in the originalMessage data + // When displaying within a IOUDetailsModal we cannot guarantee that participants are included in the originalMessage data // Because an IOUPreview of type split can never be rendered within the IOUDetailsModal, manually building the email array is only needed for non-billSplit ious const participantEmails = props.isBillSplit ? props.action.originalMessage.participants : [managerEmail, ownerEmail]; const participantAvatars = OptionsListUtils.getAvatarsForLogins(participantEmails, props.personalDetails); @@ -154,6 +156,19 @@ const IOUPreview = (props) => { const requestAmount = props.isBillSplit ? props.action.originalMessage.amount : props.iouReport.total; const requestCurrency = props.isBillSplit ? lodashGet(props.action, 'originalMessage.currency', CONST.CURRENCY.USD) : props.iouReport.currency; + const getSettledMessage = () => { + switch (lodashGet(props.action, 'originalMessage.paymentType', '')) { + case CONST.IOU.PAYMENT_TYPE.PAYPAL_ME: + return props.translate('iou.settledPaypalMe'); + case CONST.IOU.PAYMENT_TYPE.ELSEWHERE: + return props.translate('iou.settledElsewhere'); + case CONST.IOU.PAYMENT_TYPE.EXPENSIFY: + return props.translate('iou.settledExpensify'); + default: + return ''; + } + }; + const showContextMenu = (event) => { // Use action and shouldHidePayButton props to check if we are in IOUDetailsModal, // if it's true, do nothing when user long press, otherwise show context menu. @@ -177,10 +192,30 @@ const IOUPreview = (props) => { needsOffscreenAlphaCompositing > - {props.isBillSplit ? props.translate('iou.split') : props.translate('iou.cash')} - {CurrencyUtils.convertToDisplayString(requestAmount, requestCurrency)} + {props.isBillSplit ? props.translate('iou.split') : props.translate('iou.cash')} + {Boolean(getSettledMessage()) && ( + <> + + {getSettledMessage()} + + )} + + + + + + {CurrencyUtils.convertToDisplayString(requestAmount, requestCurrency)} {!props.iouReport.hasOutstandingIOU && !props.isBillSplit && ( { )} - - - + {props.isBillSplit && ( + + + + )} {!isCurrentUserManager && props.shouldShowPendingConversionMessage && ( {props.translate('iou.pendingConversionMessage')} )} - {Str.htmlDecode(lodashGet(props.action, 'originalMessage.comment', ''))} + {Str.htmlDecode(lodashGet(props.action, 'originalMessage.comment', ''))} {isCurrentUserManager && !props.shouldHidePayButton && props.iouReport.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && (