From 197dcc3acf5823e3c8eb470aa4f24e07238b0bca Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 6 Oct 2023 20:19:50 +0700 Subject: [PATCH 01/24] fix: 28969 --- src/pages/home/ReportScreen.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 78f6edcf7dd3..c13858d1ff05 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -39,6 +39,7 @@ import DragAndDropProvider from '../../components/DragAndDrop/Provider'; import usePrevious from '../../hooks/usePrevious'; import CONST from '../../CONST'; import withCurrentReportID, {withCurrentReportIDPropTypes, withCurrentReportIDDefaultProps} from '../../components/withCurrentReportID'; +import useNetwork from '../../hooks/useNetwork'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -156,6 +157,7 @@ function ReportScreen({ const prevReport = usePrevious(report); const prevUserLeavingStatus = usePrevious(userLeavingStatus); const [isBannerVisible, setIsBannerVisible] = useState(true); + const {isOffline} = useNetwork(); const reportID = getReportID(route); const {addWorkspaceRoomOrChatPendingAction, addWorkspaceRoomOrChatErrors} = ReportUtils.getReportOfflinePendingActionAndErrors(report); @@ -362,8 +364,8 @@ function ReportScreen({ // eslint-disable-next-line rulesdir/no-negated-variables const shouldShowNotFoundPage = useMemo( - () => (!firstRenderRef.current && !report.reportID && !isOptimisticDelete && !reportMetadata.isLoadingReportActions && !isLoading && !userLeavingStatus) || shouldHideReport, - [report, reportMetadata, isLoading, shouldHideReport, isOptimisticDelete, userLeavingStatus], + () => (!firstRenderRef.current && !report.reportID && (isOffline || (!reportMetadata.isLoadingReportActions && !isOptimisticDelete)) && !isLoading && !userLeavingStatus) || shouldHideReport, + [report, reportMetadata, isLoading, shouldHideReport, isOptimisticDelete, userLeavingStatus, isOffline], ); return ( From 20ddda989d726f338fe1d898812b4a42508bacda Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Wed, 29 Nov 2023 12:38:09 +0100 Subject: [PATCH 02/24] do not display new line when creating request money --- src/pages/home/report/ReportActionsList.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index e1230d7219db..6ad79f9f488a 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -335,6 +335,12 @@ function ReportActionsList({ (reportAction, index) => { let shouldDisplay = false; if (!currentUnreadMarker) { + // Check if the report type is "REPORTREVIEW" and last actor is the current user. + // Return shouldDisplay new marker action (terminate flow). + // This is to avoid displaying the new line marker when a current userrequests money. + if (reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && reportAction.childLastActorAccountID === Report.getCurrentUserAccountID()) { + return shouldDisplay; + } const nextMessage = sortedReportActions[index + 1]; const isCurrentMessageUnread = isMessageUnread(reportAction, lastReadTimeRef.current); shouldDisplay = isCurrentMessageUnread && (!nextMessage || !isMessageUnread(nextMessage, lastReadTimeRef.current)); From 6bac4f8e367029756507220784bdde6f95e6bc9f Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Wed, 29 Nov 2023 14:21:44 +0100 Subject: [PATCH 03/24] use isReportPreviewAction --- src/pages/home/report/ReportActionsList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 6ad79f9f488a..6da3c1d34eb7 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -338,7 +338,7 @@ function ReportActionsList({ // Check if the report type is "REPORTREVIEW" and last actor is the current user. // Return shouldDisplay new marker action (terminate flow). // This is to avoid displaying the new line marker when a current userrequests money. - if (reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && reportAction.childLastActorAccountID === Report.getCurrentUserAccountID()) { + if (ReportActionsUtils.isReportPreviewAction(reportAction) && reportAction.childLastActorAccountID === Report.getCurrentUserAccountID()) { return shouldDisplay; } const nextMessage = sortedReportActions[index + 1]; From 8d308c5e3b8211128b1bb8fff5ca3c595b784b8b Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Thu, 30 Nov 2023 06:39:42 +0100 Subject: [PATCH 04/24] fix review comment --- src/pages/home/report/ReportActionsList.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 6da3c1d34eb7..716a8ab695c2 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -335,17 +335,15 @@ function ReportActionsList({ (reportAction, index) => { let shouldDisplay = false; if (!currentUnreadMarker) { - // Check if the report type is "REPORTREVIEW" and last actor is the current user. - // Return shouldDisplay new marker action (terminate flow). - // This is to avoid displaying the new line marker when a current userrequests money. - if (ReportActionsUtils.isReportPreviewAction(reportAction) && reportAction.childLastActorAccountID === Report.getCurrentUserAccountID()) { - return shouldDisplay; - } const nextMessage = sortedReportActions[index + 1]; const isCurrentMessageUnread = isMessageUnread(reportAction, lastReadTimeRef.current); shouldDisplay = isCurrentMessageUnread && (!nextMessage || !isMessageUnread(nextMessage, lastReadTimeRef.current)); if (!messageManuallyMarkedUnread) { - shouldDisplay = shouldDisplay && reportAction.actorAccountID !== Report.getCurrentUserAccountID(); + // Check if the report type is "REPORTREVIEW" and last actor is the current user. + // This is to avoid displaying the new line marker when a current userrequests money. + shouldDisplay = + shouldDisplay && + (ReportActionsUtils.isReportPreviewAction(reportAction) ? reportAction.childLastActorAccountID : reportAction.actorAccountID) !== Report.getCurrentUserAccountID(); } if (shouldDisplay) { cacheUnreadMarkers.set(report.reportID, reportAction.reportActionID); From d3b47a31e727a349a0be4090a100e01094d8eb7a Mon Sep 17 00:00:00 2001 From: Yauheni Pasiukevich Date: Wed, 29 Nov 2023 17:23:46 +0100 Subject: [PATCH 05/24] Migrate 'ReportActionItemDraft.js' component to TypeScript --- .../home/report/ReportActionItemDraft.js | 22 ------------------- .../home/report/ReportActionItemDraft.tsx | 17 ++++++++++++++ 2 files changed, 17 insertions(+), 22 deletions(-) delete mode 100644 src/pages/home/report/ReportActionItemDraft.js create mode 100644 src/pages/home/report/ReportActionItemDraft.tsx diff --git a/src/pages/home/report/ReportActionItemDraft.js b/src/pages/home/report/ReportActionItemDraft.js deleted file mode 100644 index 9b3839aa78f2..000000000000 --- a/src/pages/home/report/ReportActionItemDraft.js +++ /dev/null @@ -1,22 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import {View} from 'react-native'; -import useThemeStyles from '@styles/useThemeStyles'; - -const propTypes = { - /** Children view component for this action item */ - children: PropTypes.node.isRequired, -}; - -function ReportActionItemDraft(props) { - const styles = useThemeStyles(); - return ( - - {props.children} - - ); -} - -ReportActionItemDraft.propTypes = propTypes; -ReportActionItemDraft.displayName = 'ReportActionItemDraft'; -export default ReportActionItemDraft; diff --git a/src/pages/home/report/ReportActionItemDraft.tsx b/src/pages/home/report/ReportActionItemDraft.tsx new file mode 100644 index 000000000000..b46af5401ee4 --- /dev/null +++ b/src/pages/home/report/ReportActionItemDraft.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import {View} from 'react-native'; +import useThemeStyles from '@styles/useThemeStyles'; +import ChildrenProps from '@src/types/utils/ChildrenProps'; + +function ReportActionItemDraft({children}: ChildrenProps) { + const styles = useThemeStyles(); + + return ( + + {children} + + ); +} + +ReportActionItemDraft.displayName = 'ReportActionItemDraft'; +export default ReportActionItemDraft; From 001aae314b7d0185f2fac914196ae77e853ba8ad Mon Sep 17 00:00:00 2001 From: tienifr Date: Thu, 30 Nov 2023 23:31:53 +0700 Subject: [PATCH 06/24] fix: Undefined displayed in header offline when opening left thread --- src/libs/actions/Report.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index a03488429405..852a11f93db6 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -2053,6 +2053,9 @@ function leaveRoom(reportID, isWorkspaceMemberLeavingWorkspaceRoom = false) { value: { stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS.CLOSED, + parentReportID: report.parentReportID, + parentReportActionID: report.parentReportActionID, + type: report.type, }, }, ]; From 7f23712f67187d54f915f848a7ea70e9cc4bc547 Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Fri, 1 Dec 2023 10:14:43 +0100 Subject: [PATCH 07/24] fix lint --- src/pages/home/report/ReportActionsList.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index a3d28d09da5a..99e29d3edd5e 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -342,9 +342,10 @@ function ReportActionsList({ const isWithinVisibleThreshold = scrollingVerticalOffset.current < MSG_VISIBLE_THRESHOLD ? reportAction.created < userActiveSince.current : true; // Check if the report type is "REPORTREVIEW" and last actor is the current user. // This is to avoid displaying the new line marker when a current userrequests money. - shouldDisplay = shouldDisplay && ReportActionsUtils.isReportPreviewAction(reportAction) - ? reportAction.childLastActorAccountID - : reportAction.actorAccountID !== Report.getCurrentUserAccountID() && isWithinVisibleThreshold; + shouldDisplay = + shouldDisplay && ReportActionsUtils.isReportPreviewAction(reportAction) + ? reportAction.childLastActorAccountID + : reportAction.actorAccountID !== Report.getCurrentUserAccountID() && isWithinVisibleThreshold; } if (shouldDisplay) { cacheUnreadMarkers.set(report.reportID, reportAction.reportActionID); From baf668f1f54ee128323aa1364dda36bc8f5f4cb5 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 1 Dec 2023 17:53:55 +0700 Subject: [PATCH 08/24] fix avatar for workspace thread --- src/libs/ReportUtils.ts | 2 +- src/libs/actions/Report.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index f6c3090143f4..666d90aac21e 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3849,7 +3849,7 @@ function getWhisperDisplayNames(participantAccountIDs?: number[]): string | unde * Show subscript on workspace chats / threads and expense requests */ function shouldReportShowSubscript(report: OnyxEntry): boolean { - if (isArchivedRoom(report)) { + if (isArchivedRoom(report) && !isWorkspaceThread(report)) { return false; } diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 852a11f93db6..c2cfa1ac92a2 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -2053,8 +2053,10 @@ function leaveRoom(reportID, isWorkspaceMemberLeavingWorkspaceRoom = false) { value: { stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, statusNum: CONST.REPORT.STATUS.CLOSED, + chatType: report.chatType, parentReportID: report.parentReportID, parentReportActionID: report.parentReportActionID, + policyID: report.policyID, type: report.type, }, }, From 01b27d9180977283a8c874b591e6788283fad603 Mon Sep 17 00:00:00 2001 From: Etotaziba Olei Date: Fri, 1 Dec 2023 14:28:33 +0100 Subject: [PATCH 09/24] fix failing test --- src/pages/home/report/ReportActionsList.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index d1050f4c0930..8e63f508f8ce 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -337,14 +337,13 @@ function ReportActionsList({ const nextMessage = sortedReportActions[index + 1]; const isCurrentMessageUnread = isMessageUnread(reportAction, lastReadTimeRef.current); shouldDisplay = isCurrentMessageUnread && (!nextMessage || !isMessageUnread(nextMessage, lastReadTimeRef.current)); - if (!messageManuallyMarkedUnread) { + if (shouldDisplay && !messageManuallyMarkedUnread) { const isWithinVisibleThreshold = scrollingVerticalOffset.current < MSG_VISIBLE_THRESHOLD ? reportAction.created < userActiveSince.current : true; // Check if the report type is "REPORTREVIEW" and last actor is the current user. // This is to avoid displaying the new line marker when a current userrequests money. shouldDisplay = - shouldDisplay && ReportActionsUtils.isReportPreviewAction(reportAction) - ? reportAction.childLastActorAccountID - : reportAction.actorAccountID !== Report.getCurrentUserAccountID() && isWithinVisibleThreshold; + (ReportActionsUtils.isReportPreviewAction(reportAction) ? !reportAction.childLastActorAccountID : reportAction.actorAccountID !== Report.getCurrentUserAccountID()) && + isWithinVisibleThreshold; } if (shouldDisplay) { cacheUnreadMarkers.set(report.reportID, reportAction.reportActionID); From d82f0c8f1375e6fcc5ef32e7f2f86229159adf30 Mon Sep 17 00:00:00 2001 From: Monil Bhavsar Date: Mon, 4 Dec 2023 16:41:22 +0530 Subject: [PATCH 10/24] Update hook dependency and property type --- src/pages/home/report/ReportActionsList.js | 13 ++++++------- src/types/onyx/ReportAction.ts | 3 ++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 8e63f508f8ce..183665891929 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -156,7 +156,7 @@ function ReportActionsList({ const readActionSkipped = useRef(false); const hasHeaderRendered = useRef(false); const hasFooterRendered = useRef(false); - const reportActionSize = useRef(sortedReportActions.length); + const lastVisibleActionCreatedRef = useRef(report.lastVisibleActionCreated); const lastReadTimeRef = useRef(report.lastReadTime); const linkedReportActionID = lodashGet(route, 'params.reportActionID', ''); @@ -198,15 +198,15 @@ function ReportActionsList({ } } - if (currentUnreadMarker || reportActionSize.current === sortedReportActions.length) { + if (currentUnreadMarker || lastVisibleActionCreatedRef.current === report.lastVisibleActionCreated) { return; } cacheUnreadMarkers.delete(report.reportID); - reportActionSize.current = sortedReportActions.length; + lastVisibleActionCreatedRef.current = report.lastVisibleActionCreated; setCurrentUnreadMarker(null); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [sortedReportActions.length, report.reportID]); + }, [report.lastVisibleActionCreated, report.reportID]); useEffect(() => { if (!userActiveSince.current || report.reportID !== prevReportID) { @@ -339,10 +339,9 @@ function ReportActionsList({ shouldDisplay = isCurrentMessageUnread && (!nextMessage || !isMessageUnread(nextMessage, lastReadTimeRef.current)); if (shouldDisplay && !messageManuallyMarkedUnread) { const isWithinVisibleThreshold = scrollingVerticalOffset.current < MSG_VISIBLE_THRESHOLD ? reportAction.created < userActiveSince.current : true; - // Check if the report type is "REPORTREVIEW" and last actor is the current user. - // This is to avoid displaying the new line marker when a current userrequests money. + // Prevent displaying a new marker line when report action is of type "REPORTPREVIEW" and last actor is the current user shouldDisplay = - (ReportActionsUtils.isReportPreviewAction(reportAction) ? !reportAction.childLastActorAccountID : reportAction.actorAccountID !== Report.getCurrentUserAccountID()) && + (ReportActionsUtils.isReportPreviewAction(reportAction) ? !reportAction.childLastActorAccountID : reportAction.actorAccountID) !== Report.getCurrentUserAccountID() && isWithinVisibleThreshold; } if (shouldDisplay) { diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index 64e1eb0b7c88..01d0463abda5 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -115,12 +115,13 @@ type ReportActionBase = { childStateNum?: ValueOf; childLastReceiptTransactionIDs?: string; childLastMoneyRequestComment?: string; + childLastActorAccountID?: number; timestamp?: number; reportActionTimestamp?: number; childMoneyRequestCount?: number; isFirstItem?: boolean; - /** Informations about attachments of report action */ + /** Information about attachments of report action */ attachmentInfo?: (File & {source: string; uri: string}) | Record; /** Receipt tied to report action */ From 22ec91cee8c533ae997340fd56079bb1e53b4ac4 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Mon, 4 Dec 2023 13:00:17 -0700 Subject: [PATCH 11/24] Get the parent report action using withOnyx for the money request view --- .../ReportActionItem/MoneyRequestView.js | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 0249a9f5bb11..80725a1e2531 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -29,6 +29,7 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import AnimatedEmptyStateBackground from '@pages/home/report/AnimatedEmptyStateBackground'; +import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; import iouReportPropTypes from '@pages/iouReportPropTypes'; import reportPropTypes from '@pages/reportPropTypes'; import * as StyleUtils from '@styles/StyleUtils'; @@ -51,6 +52,9 @@ const propTypes = { /** The expense report or iou report (only will have a value if this is a transaction thread) */ parentReport: iouReportPropTypes, + /** The actions from the parent report */ + parentReportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), + /** Collection of categories attached to a policy */ policyCategories: PropTypes.objectOf(categoryPropTypes), @@ -65,6 +69,7 @@ const propTypes = { const defaultProps = { parentReport: {}, + parentReportActions: {}, policyCategories: {}, transaction: { amount: 0, @@ -74,13 +79,13 @@ const defaultProps = { policyTags: {}, }; -function MoneyRequestView({report, parentReport, policyCategories, shouldShowHorizontalRule, transaction, policyTags, policy}) { +function MoneyRequestView({report, parentReport, parentReportActions, policyCategories, shouldShowHorizontalRule, transaction, policyTags, policy}) { const theme = useTheme(); const styles = useThemeStyles(); const {isSmallScreenWidth} = useWindowDimensions(); const {translate} = useLocalize(); const {canUseViolations} = usePermissions(); - const parentReportAction = ReportActionsUtils.getParentReportAction(report); + const parentReportAction = parentReportActions[report.parentReportActionID] || {}; const moneyRequestReport = parentReport; const { created: transactionDate, @@ -313,8 +318,8 @@ MoneyRequestView.displayName = 'MoneyRequestView'; export default compose( withCurrentUserPersonalDetails, withOnyx({ - parentReport: { - key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`, + session: { + key: ONYXKEYS.SESSION, }, policy: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, @@ -322,18 +327,24 @@ export default compose( policyCategories: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report.policyID}`, }, - session: { - key: ONYXKEYS.SESSION, + policyTags: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report.policyID}`, }, + parentReport: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`, + }, + parentReportActions: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '0'}`, + canEvict: false, + }, + }), + withOnyx({ transaction: { - key: ({report}) => { - const parentReportAction = ReportActionsUtils.getParentReportAction(report); + key: ({report, parentReportActions}) => { + const parentReportAction = parentReportActions[report.parentReportActionID]; const transactionID = lodashGet(parentReportAction, ['originalMessage', 'IOUTransactionID'], 0); return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; }, }, - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report.policyID}`, - }, }), )(MoneyRequestView); From eb9c843ee8e474b0cd9743120bab3feb64169de7 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Wed, 6 Dec 2023 14:19:28 +0700 Subject: [PATCH 12/24] fix search term is lost --- src/pages/workspace/SearchInputManager.js | 5 +++++ src/pages/workspace/WorkspaceInvitePage.js | 15 ++++++++++++++- src/pages/workspace/WorkspaceMembersPage.js | 20 +++++++++++++++++++- 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/pages/workspace/SearchInputManager.js diff --git a/src/pages/workspace/SearchInputManager.js b/src/pages/workspace/SearchInputManager.js new file mode 100644 index 000000000000..599f7cca6cf9 --- /dev/null +++ b/src/pages/workspace/SearchInputManager.js @@ -0,0 +1,5 @@ +// eslint-disable-next-line prefer-const +let searchInput = ''; +export default { + searchInput, +}; diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js index 4bef69c82414..dfcd1e555ed7 100644 --- a/src/pages/workspace/WorkspaceInvitePage.js +++ b/src/pages/workspace/WorkspaceInvitePage.js @@ -21,6 +21,7 @@ import * as Policy from '@userActions/Policy'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import SearchInputManager from './SearchInputManager'; import {policyDefaultProps, policyPropTypes} from './withPolicy'; import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading'; @@ -75,6 +76,15 @@ function WorkspaceInvitePage(props) { Policy.openWorkspaceInvitePage(props.route.params.policyID, _.keys(policyMemberEmailsToAccountIDs)); }; + useEffect(() => { + if (!SearchInputManager.searchInput) { + return; + } + if (SearchInputManager.searchInput) { + setSearchTerm(SearchInputManager.searchInput); + } + }, []); + useEffect(() => { Policy.clearErrors(props.route.params.policyID); openWorkspaceInvitePage(); @@ -255,7 +265,10 @@ function WorkspaceInvitePage(props) { sections={sections} textInputLabel={translate('optionsSelector.nameEmailOrPhoneNumber')} textInputValue={searchTerm} - onChangeText={setSearchTerm} + onChangeText={(value) => { + SearchInputManager.searchInput = value; + setSearchTerm(value); + }} headerMessage={headerMessage} onSelectRow={toggleOption} onConfirm={inviteUser} diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index 09b613350705..e055afc206a0 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -1,3 +1,4 @@ +import {useIsFocused} from '@react-navigation/native'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; @@ -32,6 +33,7 @@ import * as Policy from '@userActions/Policy'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import SearchInputManager from './SearchInputManager'; import {policyDefaultProps, policyPropTypes} from './withPolicy'; import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading'; @@ -85,6 +87,19 @@ function WorkspaceMembersPage(props) { const isOfflineAndNoMemberDataAvailable = _.isEmpty(props.policyMembers) && props.network.isOffline; const prevPersonalDetails = usePrevious(props.personalDetails); + const isFocusedScreen = useIsFocused(); + + useEffect(() => { + if (!SearchInputManager.searchInput) { + return; + } + if (SearchInputManager.searchInput) { + setSearchValue(SearchInputManager.searchInput); + } + }, [isFocusedScreen]); + + useEffect(() => () => (SearchInputManager.searchInput = ''), []); + /** * Get filtered personalDetails list with current policyMembers * @param {Object} policyMembers @@ -466,7 +481,10 @@ function WorkspaceMembersPage(props) { sections={[{data, indexOffset: 0, isDisabled: false}]} textInputLabel={props.translate('optionsSelector.findMember')} textInputValue={searchValue} - onChangeText={setSearchValue} + onChangeText={(value) => { + SearchInputManager.searchInput = value; + setSearchValue(value); + }} headerMessage={getHeaderMessage()} headerContent={getHeaderContent()} onSelectRow={(item) => toggleUser(item.accountID)} From f931e044e6bebd0468b01db477e4af47f8d94998 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Wed, 6 Dec 2023 21:10:43 +0700 Subject: [PATCH 13/24] fix update based on suggestions --- src/pages/workspace/WorkspaceInvitePage.js | 4 +--- src/pages/workspace/WorkspaceMembersPage.js | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js index dfcd1e555ed7..b18c234ea44d 100644 --- a/src/pages/workspace/WorkspaceInvitePage.js +++ b/src/pages/workspace/WorkspaceInvitePage.js @@ -80,9 +80,7 @@ function WorkspaceInvitePage(props) { if (!SearchInputManager.searchInput) { return; } - if (SearchInputManager.searchInput) { - setSearchTerm(SearchInputManager.searchInput); - } + setSearchTerm(SearchInputManager.searchInput); }, []); useEffect(() => { diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js index e055afc206a0..d5cdbcfc69d8 100644 --- a/src/pages/workspace/WorkspaceMembersPage.js +++ b/src/pages/workspace/WorkspaceMembersPage.js @@ -93,9 +93,7 @@ function WorkspaceMembersPage(props) { if (!SearchInputManager.searchInput) { return; } - if (SearchInputManager.searchInput) { - setSearchValue(SearchInputManager.searchInput); - } + setSearchValue(SearchInputManager.searchInput); }, [isFocusedScreen]); useEffect(() => () => (SearchInputManager.searchInput = ''), []); From 7142a459f66d653c9ed609d7974402b5ef499734 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Wed, 6 Dec 2023 23:41:12 +0700 Subject: [PATCH 14/24] fix clear input once rhn closed --- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index a78b38728136..6684e476b4f3 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -13,6 +13,7 @@ import type {AuthScreensParamList} from '@navigation/types'; import DemoSetupPage from '@pages/DemoSetupPage'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import DesktopSignInRedirectPage from '@pages/signin/DesktopSignInRedirectPage'; +import SearchInputManager from '@pages/workspace/SearchInputManager'; import useThemeStyles from '@styles/useThemeStyles'; import * as App from '@userActions/App'; import * as Download from '@userActions/Download'; @@ -123,6 +124,8 @@ const modalScreenListeners = { Modal.setModalVisibility(true); }, beforeRemove: () => { + // Clear search input (WorkspaceMembersPage) when modal is closed + SearchInputManager.searchInput = ''; Modal.setModalVisibility(false); }, }; From d180ba9d9d53898397363a1cba5add7918e31e4c Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Thu, 7 Dec 2023 00:44:15 +0700 Subject: [PATCH 15/24] fix update comment --- src/libs/Navigation/AppNavigator/AuthScreens.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 6684e476b4f3..5e8a9f502dc5 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -124,7 +124,7 @@ const modalScreenListeners = { Modal.setModalVisibility(true); }, beforeRemove: () => { - // Clear search input (WorkspaceMembersPage) when modal is closed + // Clear search input (WorkspaceInvitePage) when modal is closed SearchInputManager.searchInput = ''; Modal.setModalVisibility(false); }, From 7439a3d6697bbf4715e231e388355ad3a06303ce Mon Sep 17 00:00:00 2001 From: OSBotify Date: Wed, 6 Dec 2023 19:46:43 +0000 Subject: [PATCH 16/24] Update version to 1.4.8-3 --- 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 f7a83db89d9a..1138beb7e98b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -91,8 +91,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001040802 - versionName "1.4.8-2" + versionCode 1001040803 + versionName "1.4.8-3" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 9465f768afe1..807c235eedb5 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.8.2 + 1.4.8.3 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index b4ae3184e624..3800aa4b7da1 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.8.2 + 1.4.8.3 diff --git a/package-lock.json b/package-lock.json index 5e459506dccd..ae679dfd89ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.8-2", + "version": "1.4.8-3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.8-2", + "version": "1.4.8-3", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 6c3eb5a589b4..15dfe3f81d69 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.8-2", + "version": "1.4.8-3", "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 deda6ae510f1e1ef1599c8c6ee45d91fe58660c5 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Wed, 6 Dec 2023 20:26:54 +0000 Subject: [PATCH 17/24] Update version to 1.4.9-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 1138beb7e98b..25010c93da6f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -91,8 +91,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001040803 - versionName "1.4.8-3" + versionCode 1001040900 + versionName "1.4.9-0" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 807c235eedb5..9657a6d9b4e6 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.4.8 + 1.4.9 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.8.3 + 1.4.9.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 3800aa4b7da1..77b0f97c9e9b 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.4.8 + 1.4.9 CFBundleSignature ???? CFBundleVersion - 1.4.8.3 + 1.4.9.0 diff --git a/package-lock.json b/package-lock.json index ae679dfd89ca..b87f13d8a8cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.8-3", + "version": "1.4.9-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.8-3", + "version": "1.4.9-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 15dfe3f81d69..58d505dbdead 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.8-3", + "version": "1.4.9-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 9d31e4b9e7f85d17988cb1efd7cac6c48e700e46 Mon Sep 17 00:00:00 2001 From: Yuwen Memon Date: Wed, 6 Dec 2023 15:36:09 -0800 Subject: [PATCH 18/24] Revert "translate invite member to room" --- src/languages/en.ts | 6 - src/languages/es.ts | 6 - src/libs/Localize/index.ts | 46 +------ src/libs/MessageElement.ts | 11 -- src/libs/PersonalDetailsUtils.js | 13 -- src/libs/ReportActionsUtils.ts | 113 +----------------- src/libs/ReportUtils.ts | 41 ++++++- src/libs/SidebarUtils.ts | 10 +- .../report/ContextMenu/ContextMenuActions.js | 4 +- .../home/report/ReportActionItemMessage.js | 15 --- src/types/onyx/OriginalMessage.ts | 1 - tests/unit/LocalizeTests.js | 8 +- 12 files changed, 61 insertions(+), 213 deletions(-) delete mode 100644 src/libs/MessageElement.ts diff --git a/src/languages/en.ts b/src/languages/en.ts index a276de4e0f7c..817f06f6b344 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1547,12 +1547,6 @@ export default { invitePeople: 'Invite new members', genericFailureMessage: 'An error occurred inviting the user to the workspace, please try again.', pleaseEnterValidLogin: `Please ensure the email or phone number is valid (e.g. ${CONST.EXAMPLE_PHONE_NUMBER}).`, - user: 'user', - users: 'users', - invited: 'invited', - removed: 'removed', - to: 'to', - from: 'from', }, inviteMessage: { inviteMessageTitle: 'Add message', diff --git a/src/languages/es.ts b/src/languages/es.ts index 290d80a6f65d..b219021daa0f 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1569,12 +1569,6 @@ export default { invitePeople: 'Invitar nuevos miembros', genericFailureMessage: 'Se produjo un error al invitar al usuario al espacio de trabajo. Vuelva a intentarlo..', pleaseEnterValidLogin: `Asegúrese de que el correo electrónico o el número de teléfono sean válidos (p. ej. ${CONST.EXAMPLE_PHONE_NUMBER}).`, - user: 'usuario', - users: 'usuarios', - invited: 'invitó', - removed: 'eliminó', - to: 'a', - from: 'de', }, inviteMessage: { inviteMessageTitle: 'Añadir un mensaje', diff --git a/src/libs/Localize/index.ts b/src/libs/Localize/index.ts index 77c34ebdc576..488ff0d9b98a 100644 --- a/src/libs/Localize/index.ts +++ b/src/libs/Localize/index.ts @@ -1,7 +1,6 @@ import * as RNLocalize from 'react-native-localize'; import Onyx from 'react-native-onyx'; import Log from '@libs/Log'; -import {MessageElementBase, MessageTextElement} from '@libs/MessageElement'; import Config from '@src/CONFIG'; import CONST from '@src/CONST'; import translations from '@src/languages/translations'; @@ -122,48 +121,15 @@ function translateIfPhraseKey(message: MaybePhraseKey): string { } } -function getPreferredListFormat(): Intl.ListFormat { - if (!CONJUNCTION_LIST_FORMATS_FOR_LOCALES) { - init(); - } - - return CONJUNCTION_LIST_FORMATS_FOR_LOCALES[BaseLocaleListener.getPreferredLocale()]; -} - /** * Format an array into a string with comma and "and" ("a dog, a cat and a chicken") */ -function formatList(components: string[]) { - const listFormat = getPreferredListFormat(); - return listFormat.format(components); -} - -function formatMessageElementList(elements: readonly E[]): ReadonlyArray { - const listFormat = getPreferredListFormat(); - const parts = listFormat.formatToParts(elements.map((e) => e.content)); - const resultElements: Array = []; - - let nextElementIndex = 0; - for (const part of parts) { - if (part.type === 'element') { - /** - * The standard guarantees that all input elements will be present in the constructed parts, each exactly - * once, and without any modifications: https://tc39.es/ecma402/#sec-createpartsfromlist - */ - const element = elements[nextElementIndex++]; - - resultElements.push(element); - } else { - const literalElement: MessageTextElement = { - kind: 'text', - content: part.value, - }; - - resultElements.push(literalElement); - } +function arrayToString(anArray: string[]) { + if (!CONJUNCTION_LIST_FORMATS_FOR_LOCALES) { + init(); } - - return resultElements; + const listFormat = CONJUNCTION_LIST_FORMATS_FOR_LOCALES[BaseLocaleListener.getPreferredLocale()]; + return listFormat.format(anArray); } /** @@ -173,5 +139,5 @@ function getDevicePreferredLocale(): string { return RNLocalize.findBestAvailableLanguage([CONST.LOCALES.EN, CONST.LOCALES.ES])?.languageTag ?? CONST.LOCALES.DEFAULT; } -export {translate, translateLocal, translateIfPhraseKey, formatList, formatMessageElementList, getDevicePreferredLocale}; +export {translate, translateLocal, translateIfPhraseKey, arrayToString, getDevicePreferredLocale}; export type {PhraseParameters, Phrase, MaybePhraseKey}; diff --git a/src/libs/MessageElement.ts b/src/libs/MessageElement.ts deleted file mode 100644 index 584d7e1e289a..000000000000 --- a/src/libs/MessageElement.ts +++ /dev/null @@ -1,11 +0,0 @@ -type MessageElementBase = { - readonly kind: string; - readonly content: string; -}; - -type MessageTextElement = { - readonly kind: 'text'; - readonly content: string; -} & MessageElementBase; - -export type {MessageElementBase, MessageTextElement}; diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js index 8a4151391453..560480dcec9d 100644 --- a/src/libs/PersonalDetailsUtils.js +++ b/src/libs/PersonalDetailsUtils.js @@ -197,18 +197,6 @@ function getFormattedAddress(privatePersonalDetails) { return formattedAddress.trim().replace(/,$/, ''); } -/** - * @param {Object} personalDetail - details object - * @returns {String | undefined} - The effective display name - */ -function getEffectiveDisplayName(personalDetail) { - if (personalDetail) { - return LocalePhoneNumber.formatPhoneNumber(personalDetail.login) || personalDetail.displayName; - } - - return undefined; -} - export { getDisplayNameOrDefault, getPersonalDetailsByIDs, @@ -218,5 +206,4 @@ export { getFormattedAddress, getFormattedStreet, getStreetLines, - getEffectiveDisplayName, }; diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts index 2bc24c1706e6..6dc735ebd8b7 100644 --- a/src/libs/ReportActionsUtils.ts +++ b/src/libs/ReportActionsUtils.ts @@ -5,17 +5,14 @@ import OnyxUtils from 'react-native-onyx/lib/utils'; import {ValueOf} from 'type-fest'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import {ActionName, ChangeLog} from '@src/types/onyx/OriginalMessage'; +import {ActionName} from '@src/types/onyx/OriginalMessage'; import Report from '@src/types/onyx/Report'; -import ReportAction, {Message, ReportActions} from '@src/types/onyx/ReportAction'; +import ReportAction, {ReportActions} from '@src/types/onyx/ReportAction'; import {EmptyObject, isEmptyObject} from '@src/types/utils/EmptyObject'; import * as CollectionUtils from './CollectionUtils'; import * as Environment from './Environment/Environment'; import isReportMessageAttachment from './isReportMessageAttachment'; -import * as Localize from './Localize'; import Log from './Log'; -import {MessageElementBase, MessageTextElement} from './MessageElement'; -import * as PersonalDetailsUtils from './PersonalDetailsUtils'; type LastVisibleMessage = { lastMessageTranslationKey?: string; @@ -23,19 +20,6 @@ type LastVisibleMessage = { lastMessageHtml?: string; }; -type MemberChangeMessageUserMentionElement = { - readonly kind: 'userMention'; - readonly accountID: number; -} & MessageElementBase; - -type MemberChangeMessageRoomReferenceElement = { - readonly kind: 'roomReference'; - readonly roomName: string; - readonly roomID: number; -} & MessageElementBase; - -type MemberChangeMessageElement = MessageTextElement | MemberChangeMessageUserMentionElement | MemberChangeMessageRoomReferenceElement; - const allReports: OnyxCollection = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, @@ -116,7 +100,7 @@ function isReimbursementQueuedAction(reportAction: OnyxEntry) { return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTQUEUED; } -function isMemberChangeAction(reportAction: OnyxEntry) { +function isChannelLogMemberAction(reportAction: OnyxEntry) { return ( reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM || reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.REMOVE_FROM_ROOM || @@ -125,10 +109,6 @@ function isMemberChangeAction(reportAction: OnyxEntry) { ); } -function isInviteMemberAction(reportAction: OnyxEntry) { - return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM || reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG.INVITE_TO_ROOM; -} - function isReimbursementDeQueuedAction(reportAction: OnyxEntry): boolean { return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENTDEQUEUED; } @@ -669,89 +649,6 @@ function isNotifiableReportAction(reportAction: OnyxEntry): boolea return actions.includes(reportAction.actionName); } -function getMemberChangeMessageElements(reportAction: OnyxEntry): readonly MemberChangeMessageElement[] { - const isInviteAction = isInviteMemberAction(reportAction); - - // Currently, we only render messages when members are invited - const verb = isInviteAction ? Localize.translateLocal('workspace.invite.invited') : Localize.translateLocal('workspace.invite.removed'); - - const originalMessage = reportAction?.originalMessage as ChangeLog; - const targetAccountIDs: number[] = originalMessage?.targetAccountIDs ?? []; - const personalDetails = PersonalDetailsUtils.getPersonalDetailsByIDs(targetAccountIDs, 0); - - const mentionElements = targetAccountIDs.map((accountID): MemberChangeMessageUserMentionElement => { - const personalDetail = personalDetails.find((personal) => personal.accountID === accountID); - const handleText = PersonalDetailsUtils.getEffectiveDisplayName(personalDetail) ?? Localize.translateLocal('common.hidden'); - - return { - kind: 'userMention', - content: `@${handleText}`, - accountID, - }; - }); - - const buildRoomElements = (): readonly MemberChangeMessageElement[] => { - const roomName = originalMessage?.roomName; - - if (roomName) { - const preposition = isInviteAction ? ` ${Localize.translateLocal('workspace.invite.to')} ` : ` ${Localize.translateLocal('workspace.invite.from')} `; - - if (originalMessage.reportID) { - return [ - { - kind: 'text', - content: preposition, - }, - { - kind: 'roomReference', - roomName, - roomID: originalMessage.reportID, - content: roomName, - }, - ]; - } - } - - return []; - }; - - return [ - { - kind: 'text', - content: `${verb} `, - }, - ...Localize.formatMessageElementList(mentionElements), - ...buildRoomElements(), - ]; -} - -function getMemberChangeMessageFragment(reportAction: OnyxEntry): Message { - const messageElements: readonly MemberChangeMessageElement[] = getMemberChangeMessageElements(reportAction); - const html = messageElements - .map((messageElement) => { - switch (messageElement.kind) { - case 'userMention': - return ``; - case 'roomReference': - return `${messageElement.roomName}`; - default: - return messageElement.content; - } - }) - .join(''); - - return { - html: `${html}`, - text: reportAction?.message ? reportAction?.message[0].text : '', - type: CONST.REPORT.MESSAGE.TYPE.COMMENT, - }; -} - -function getMemberChangeMessagePlainText(reportAction: OnyxEntry): string { - const messageElements = getMemberChangeMessageElements(reportAction); - return messageElements.map((element) => element.content).join(''); -} - /** * Helper method to determine if the provided accountID has made a request on the specified report. * @@ -814,9 +711,7 @@ export { shouldReportActionBeVisibleAsLastAction, hasRequestFromCurrentAccount, getFirstVisibleReportActionID, - isMemberChangeAction, - getMemberChangeMessageFragment, - getMemberChangeMessagePlainText, + isChannelLogMemberAction, isReimbursementDeQueuedAction, }; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 84b2283681c6..1266f145de30 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -18,7 +18,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import {Beta, Login, PersonalDetails, Policy, PolicyTags, Report, ReportAction, Session, Transaction} from '@src/types/onyx'; import {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; -import {IOUMessage, OriginalMessageActionName} from '@src/types/onyx/OriginalMessage'; +import {ChangeLog, IOUMessage, OriginalMessageActionName} from '@src/types/onyx/OriginalMessage'; import {Message, ReportActions} from '@src/types/onyx/ReportAction'; import {Receipt, WaypointCollection} from '@src/types/onyx/Transaction'; import DeepValueOf from '@src/types/utils/DeepValueOf'; @@ -4174,6 +4174,44 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry) }); } +/** + * Return room channel log display message + */ +function getChannelLogMemberMessage(reportAction: OnyxEntry): string { + const verb = + reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM || reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG.INVITE_TO_ROOM + ? 'invited' + : 'removed'; + + const mentions = (reportAction?.originalMessage as ChangeLog)?.targetAccountIDs?.map(() => { + const personalDetail = allPersonalDetails?.accountID; + const displayNameOrLogin = LocalePhoneNumber.formatPhoneNumber(personalDetail?.login ?? '') || (personalDetail?.displayName ?? '') || Localize.translateLocal('common.hidden'); + return `@${displayNameOrLogin}`; + }); + + const lastMention = mentions?.pop(); + let message = ''; + + if (mentions?.length === 0) { + message = `${verb} ${lastMention}`; + } else if (mentions?.length === 1) { + message = `${verb} ${mentions?.[0]} and ${lastMention}`; + } else { + message = `${verb} ${mentions?.join(', ')}, and ${lastMention}`; + } + + const roomName = (reportAction?.originalMessage as ChangeLog)?.roomName ?? ''; + if (roomName) { + const preposition = + reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM || reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG.INVITE_TO_ROOM + ? ' to' + : ' from'; + message += `${preposition} ${roomName}`; + } + + return message; +} + /** * Checks if a report is a group chat. * @@ -4408,6 +4446,7 @@ export { getReimbursementQueuedActionMessage, getReimbursementDeQueuedActionMessage, getPersonalDetailsForAccountID, + getChannelLogMemberMessage, getRoom, shouldDisableWelcomeMessage, navigateToPrivateNotes, diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts index 6e382e11b49b..bace29e06d28 100644 --- a/src/libs/SidebarUtils.ts +++ b/src/libs/SidebarUtils.ts @@ -375,17 +375,17 @@ function getOptionData( const targetAccountIDs = lastAction?.originalMessage?.targetAccountIDs ?? []; const verb = lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM || lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG.INVITE_TO_ROOM - ? Localize.translate(preferredLocale, 'workspace.invite.invited') - : Localize.translate(preferredLocale, 'workspace.invite.removed'); - const users = Localize.translate(preferredLocale, targetAccountIDs.length > 1 ? 'workspace.invite.users' : 'workspace.invite.user'); + ? 'invited' + : 'removed'; + const users = targetAccountIDs.length > 1 ? 'users' : 'user'; result.alternateText = `${verb} ${targetAccountIDs.length} ${users}`; const roomName = lastAction?.originalMessage?.roomName ?? ''; if (roomName) { const preposition = lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM || lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG.INVITE_TO_ROOM - ? ` ${Localize.translate(preferredLocale, 'workspace.invite.to')}` - : ` ${Localize.translate(preferredLocale, 'workspace.invite.from')}`; + ? ' to' + : ' from'; result.alternateText += `${preposition} ${roomName}`; } } else if (lastAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && lastActorDisplayName && lastMessageTextFromReport) { diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 6c645bc87486..4f35926c5957 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -281,8 +281,8 @@ export default [ } else if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { const displayMessage = ReportUtils.getIOUReportActionDisplayMessage(reportAction); Clipboard.setString(displayMessage); - } else if (ReportActionsUtils.isMemberChangeAction(reportAction)) { - const logMessage = ReportActionsUtils.getMemberChangeMessagePlainText(reportAction); + } else if (ReportActionsUtils.isChannelLogMemberAction(reportAction)) { + const logMessage = ReportUtils.getChannelLogMemberMessage(reportAction); Clipboard.setString(logMessage); } else if (content) { const parser = new ExpensiMark(); diff --git a/src/pages/home/report/ReportActionItemMessage.js b/src/pages/home/report/ReportActionItemMessage.js index 46e0438f250a..2265530f29a1 100644 --- a/src/pages/home/report/ReportActionItemMessage.js +++ b/src/pages/home/report/ReportActionItemMessage.js @@ -8,7 +8,6 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import useThemeStyles from '@styles/useThemeStyles'; import CONST from '@src/CONST'; -import TextCommentFragment from './comment/TextCommentFragment'; import ReportActionItemFragment from './ReportActionItemFragment'; import reportActionPropTypes from './reportActionPropTypes'; @@ -41,20 +40,6 @@ function ReportActionItemMessage(props) { const styles = useThemeStyles(); const fragments = _.compact(props.action.previousMessage || props.action.message); const isIOUReport = ReportActionsUtils.isMoneyRequestAction(props.action); - if (ReportActionsUtils.isMemberChangeAction(props.action)) { - const fragment = ReportActionsUtils.getMemberChangeMessageFragment(props.action); - - return ( - - ); - } - let iouMessage; if (isIOUReport) { const iouReportID = lodashGet(props.action, 'originalMessage.IOUReportID'); diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 72ea275e3ba3..f76fbd5ffd7d 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -140,7 +140,6 @@ type ChronosOOOTimestamp = { type ChangeLog = { targetAccountIDs?: number[]; roomName?: string; - reportID?: number; }; type ChronosOOOEvent = { diff --git a/tests/unit/LocalizeTests.js b/tests/unit/LocalizeTests.js index 7693a0a4a88d..4c89d587fc06 100644 --- a/tests/unit/LocalizeTests.js +++ b/tests/unit/LocalizeTests.js @@ -15,7 +15,7 @@ describe('localize', () => { afterEach(() => Onyx.clear()); - describe('formatList', () => { + describe('arrayToString', () => { test.each([ [ [], @@ -52,9 +52,9 @@ describe('localize', () => { [CONST.LOCALES.ES]: 'rory, vit e ionatan', }, ], - ])('formatList(%s)', (input, {[CONST.LOCALES.DEFAULT]: expectedOutput, [CONST.LOCALES.ES]: expectedOutputES}) => { - expect(Localize.formatList(input)).toBe(expectedOutput); - return Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, CONST.LOCALES.ES).then(() => expect(Localize.formatList(input)).toBe(expectedOutputES)); + ])('arrayToSpokenList(%s)', (input, {[CONST.LOCALES.DEFAULT]: expectedOutput, [CONST.LOCALES.ES]: expectedOutputES}) => { + expect(Localize.arrayToString(input)).toBe(expectedOutput); + return Onyx.set(ONYXKEYS.NVP_PREFERRED_LOCALE, CONST.LOCALES.ES).then(() => expect(Localize.arrayToString(input)).toBe(expectedOutputES)); }); }); }); From 3827a9ce47f12f7c004339281c34a76f3a4c286b Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 7 Dec 2023 00:05:00 +0000 Subject: [PATCH 19/24] Update version to 1.4.9-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 25010c93da6f..5bf287cc784b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -91,8 +91,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001040900 - versionName "1.4.9-0" + versionCode 1001040901 + versionName "1.4.9-1" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 9657a6d9b4e6..e6ff025496f2 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.9.0 + 1.4.9.1 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 77b0f97c9e9b..3bf704107dde 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.9.0 + 1.4.9.1 diff --git a/package-lock.json b/package-lock.json index b87f13d8a8cd..e708bbb08809 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.9-0", + "version": "1.4.9-1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.9-0", + "version": "1.4.9-1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 58d505dbdead..b014365c3dd5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.9-0", + "version": "1.4.9-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 f4a3bcf40351d2709609e24d27baf477d148290f Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 6 Dec 2023 15:11:44 -1000 Subject: [PATCH 20/24] Revert "Only allow alphabetic and latin characters for some fields in `CompanyStep`" --- src/libs/ValidationUtils.ts | 94 +++++++++---------- src/pages/ReimbursementAccount/CompanyStep.js | 8 -- 2 files changed, 47 insertions(+), 55 deletions(-) diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index 0adacac4035a..388020bc0d6d 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -30,6 +30,17 @@ function validateCardNumber(value: string): boolean { return sum % 10 === 0; } +/** + * Validating that this is a valid address (PO boxes are not allowed) + */ +function isValidAddress(value: string): boolean { + if (!CONST.REGEX.ANY_VALUE.test(value)) { + return false; + } + + return !CONST.REGEX.PO_BOX.test(value); +} + /** * Validate date fields */ @@ -193,6 +204,40 @@ function isValidWebsite(url: string): boolean { return new RegExp(`^${URL_REGEX_WITH_REQUIRED_PROTOCOL}$`, 'i').test(url) && isLowerCase; } +function validateIdentity(identity: Record): Record { + const requiredFields = ['firstName', 'lastName', 'street', 'city', 'zipCode', 'state', 'ssnLast4', 'dob']; + const errors: Record = {}; + + // Check that all required fields are filled + requiredFields.forEach((fieldName) => { + if (isRequiredFulfilled(identity[fieldName])) { + return; + } + errors[fieldName] = true; + }); + + if (!isValidAddress(identity.street)) { + errors.street = true; + } + + if (!isValidZipCode(identity.zipCode)) { + errors.zipCode = true; + } + + // dob field has multiple validations/errors, we are handling it temporarily like this. + if (!isValidDate(identity.dob) || !meetsMaximumAgeRequirement(identity.dob)) { + errors.dob = true; + } else if (!meetsMinimumAgeRequirement(identity.dob)) { + errors.dobAge = true; + } + + if (!isValidSSNLastFour(identity.ssnLast4)) { + errors.ssnLast4 = true; + } + + return errors; +} + function isValidUSPhone(phoneNumber = '', isCountryCodeOptional?: boolean): boolean { const phone = phoneNumber || ''; const regionCode = isCountryCodeOptional ? CONST.COUNTRY.US : undefined; @@ -259,51 +304,6 @@ function isValidPersonName(value: string) { return /^[^\d^!#$%*=<>;{}"]+$/.test(value); } -/** - * Validating that this is a valid address (PO boxes are not allowed) - */ -function isValidAddress(value: string): boolean { - if (!isValidLegalName(value)) { - return false; - } - - return !CONST.REGEX.PO_BOX.test(value); -} - -function validateIdentity(identity: Record): Record { - const requiredFields = ['firstName', 'lastName', 'street', 'city', 'zipCode', 'state', 'ssnLast4', 'dob']; - const errors: Record = {}; - - // Check that all required fields are filled - requiredFields.forEach((fieldName) => { - if (isRequiredFulfilled(identity[fieldName])) { - return; - } - errors[fieldName] = true; - }); - - if (!isValidAddress(identity.street)) { - errors.street = true; - } - - if (!isValidZipCode(identity.zipCode)) { - errors.zipCode = true; - } - - // dob field has multiple validations/errors, we are handling it temporarily like this. - if (!isValidDate(identity.dob) || !meetsMaximumAgeRequirement(identity.dob)) { - errors.dob = true; - } else if (!meetsMinimumAgeRequirement(identity.dob)) { - errors.dobAge = true; - } - - if (!isValidSSNLastFour(identity.ssnLast4)) { - errors.ssnLast4 = true; - } - - return errors; -} - /** * Checks if the provided string includes any of the provided reserved words */ @@ -384,6 +384,7 @@ export { meetsMinimumAgeRequirement, meetsMaximumAgeRequirement, getAgeRequirementError, + isValidAddress, isValidDate, isValidPastDate, isValidSecurityCode, @@ -395,6 +396,7 @@ export { getFieldRequiredErrors, isValidUSPhone, isValidWebsite, + validateIdentity, isValidTwoFactorCode, isNumericWithSpecialChars, isValidRoutingNumber, @@ -407,8 +409,6 @@ export { isValidValidateCode, isValidDisplayName, isValidLegalName, - isValidAddress, - validateIdentity, doesContainReservedWord, isNumeric, isValidAccountRoute, diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js index d7d622d309d6..f1d62eef89ae 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -88,10 +88,6 @@ function CompanyStep({reimbursementAccount, reimbursementAccountDraft, getDefaul ]; const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields); - if (values.companyName && !ValidationUtils.isValidLegalName(values.companyName)) { - errors.companyName = 'bankAccount.error.companyName'; - } - if (values.addressStreet && !ValidationUtils.isValidAddress(values.addressStreet)) { errors.addressStreet = 'bankAccount.error.addressStreet'; } @@ -100,10 +96,6 @@ function CompanyStep({reimbursementAccount, reimbursementAccountDraft, getDefaul errors.addressZipCode = 'bankAccount.error.zipCode'; } - if (values.addressCity && !ValidationUtils.isValidLegalName(values.addressCity)) { - errors.addressCity = 'bankAccount.error.addressCity'; - } - if (values.companyPhone && !ValidationUtils.isValidUSPhone(values.companyPhone, true)) { errors.companyPhone = 'bankAccount.error.phoneNumber'; } From 9a8f59b1d33ec78e1ea93ab6df33bf4085fa1d25 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 6 Dec 2023 15:26:12 -1000 Subject: [PATCH 21/24] Fix deep linking --- .../HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js index 8f1406439be9..0c36bc36c11e 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js +++ b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js @@ -62,7 +62,7 @@ function AnchorRenderer(props) { key={props.key} displayName={displayName} // Only pass the press handler for internal links. For public links or whitelisted internal links fallback to default link handling - onPress={internalNewExpensifyPath || internalExpensifyPath ? Link.openLink : undefined} + onPress={() => internalNewExpensifyPath || internalExpensifyPath ? Link.openLink(attrHref, environmentURL, isAttachment) : undefined} > From 1e8bb05c0b886da4ff2c6baca612eeb846f739f6 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 6 Dec 2023 15:27:18 -1000 Subject: [PATCH 22/24] Pass undefined to onPress --- .../HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js index 0c36bc36c11e..2216f88d1055 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js +++ b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js @@ -61,8 +61,9 @@ function AnchorRenderer(props) { style={{...props.style, ...parentStyle, ...styles.textUnderlinePositionUnder, ...styles.textDecorationSkipInkNone}} key={props.key} displayName={displayName} + // Only pass the press handler for internal links. For public links or whitelisted internal links fallback to default link handling - onPress={() => internalNewExpensifyPath || internalExpensifyPath ? Link.openLink(attrHref, environmentURL, isAttachment) : undefined} + onPress={(internalNewExpensifyPath || internalExpensifyPath) ? () => Link.openLink(attrHref, environmentURL, isAttachment) : undefined} > From c9df3705ed7af717c80b264cc3dbb5bf2aec8ce9 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 6 Dec 2023 15:34:16 -1000 Subject: [PATCH 23/24] Fix prettier --- .../HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js index 2216f88d1055..49642308a357 100644 --- a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js +++ b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js @@ -61,9 +61,8 @@ function AnchorRenderer(props) { style={{...props.style, ...parentStyle, ...styles.textUnderlinePositionUnder, ...styles.textDecorationSkipInkNone}} key={props.key} displayName={displayName} - // Only pass the press handler for internal links. For public links or whitelisted internal links fallback to default link handling - onPress={(internalNewExpensifyPath || internalExpensifyPath) ? () => Link.openLink(attrHref, environmentURL, isAttachment) : undefined} + onPress={internalNewExpensifyPath || internalExpensifyPath ? () => Link.openLink(attrHref, environmentURL, isAttachment) : undefined} > From b0268fab8826bb964ad4c8450c342c27e23d0d50 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 7 Dec 2023 09:29:29 +0000 Subject: [PATCH 24/24] Update version to 1.4.9-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 5bf287cc784b..04d711009c10 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -91,8 +91,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001040901 - versionName "1.4.9-1" + versionCode 1001040902 + versionName "1.4.9-2" } flavorDimensions "default" diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index e6ff025496f2..07afc5a85593 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.9.1 + 1.4.9.2 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 3bf704107dde..a434ffdc5757 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.9.1 + 1.4.9.2 diff --git a/package-lock.json b/package-lock.json index e708bbb08809..6e5b51fa4526 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.9-1", + "version": "1.4.9-2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.9-1", + "version": "1.4.9-2", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index b014365c3dd5..8191454ef138 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.9-1", + "version": "1.4.9-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.",