From 7760d8c5e13b54881f72dce468403050084b1842 Mon Sep 17 00:00:00 2001
From: OSBotify <76178356+OSBotify@users.noreply.github.com>
Date: Fri, 28 Apr 2023 02:03:42 -0400
Subject: [PATCH 1/2] Merge pull request #18127 from
Expensify/version-BUILD-DBC4DBF7-B37D-4C4F-B64C-B0A81050AB94
Update version to 1.3.7-3 on main
(cherry picked from commit 243e791d7ebe26f8e251b9b4d7727e940bea14dd)
---
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 4101c0b32406..62efe3cfda16 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 1001030702
- versionName "1.3.7-2"
+ versionCode 1001030703
+ versionName "1.3.7-3"
}
splits {
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index 00d70b1cee19..1570a2a7e68a 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -30,7 +30,7 @@
CFBundleVersion
- 1.3.7.2
+ 1.3.7.3
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index 308ccc8dfd24..65d1aebf4b71 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -19,6 +19,6 @@
CFBundleSignature
????
CFBundleVersion
- 1.3.7.2
+ 1.3.7.3
diff --git a/package-lock.json b/package-lock.json
index eaacd0b413fa..91b6ec00fac0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "1.3.7-2",
+ "version": "1.3.7-3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "1.3.7-2",
+ "version": "1.3.7-3",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
diff --git a/package.json b/package.json
index a435e0ccbe7c..ef9f4f1f31fc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.3.7-2",
+ "version": "1.3.7-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 e8a9c082136cb4ad2d6d04f7a85f0cb8c5e6c697 Mon Sep 17 00:00:00 2001
From: Jasper Huang
Date: Thu, 27 Apr 2023 22:55:01 -0700
Subject: [PATCH 2/2] Merge pull request #18114 from
Expensify/jasper-fixPublicAnnounceInitialReport
Allow navigating to public announce rooms as the initial report after signing in/signing up
(cherry picked from commit 1c749c07cf307cf9689fbc1d9794f74a58ab935e)
---
.../AppNavigator/MainDrawerNavigator.js | 18 ++++-
src/libs/ReportUtils.js | 55 ++++++++++----
src/libs/actions/App.js | 72 +++++++++++--------
tests/actions/SessionTest.js | 1 +
tests/unit/NetworkTest.js | 1 +
5 files changed, 101 insertions(+), 46 deletions(-)
diff --git a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js
index 9c8ae24a2749..9f582c2df9d6 100644
--- a/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js
+++ b/src/libs/Navigation/AppNavigator/MainDrawerNavigator.js
@@ -9,6 +9,7 @@ import SCREENS from '../../../SCREENS';
import Permissions from '../../Permissions';
import Timing from '../../actions/Timing';
import CONST from '../../../CONST';
+import * as App from '../../actions/App';
// Screens
import ReportScreen from '../../../pages/home/ReportScreen';
@@ -35,6 +36,8 @@ const propTypes = {
type: PropTypes.string,
})),
+ isFirstTimeNewExpensifyUser: PropTypes.bool,
+
route: PropTypes.shape({
params: PropTypes.shape({
openOnAdminRoom: PropTypes.bool,
@@ -48,6 +51,7 @@ const defaultProps = {
reports: {},
betas: [],
policies: {},
+ isFirstTimeNewExpensifyUser: false,
};
/**
@@ -56,11 +60,12 @@ const defaultProps = {
* @param {Object} reports
* @param {Boolean} [ignoreDefaultRooms]
* @param {Object} policies
+ * @param {Boolean} isFirstTimeNewExpensifyUser
* @param {Boolean} openOnAdminRoom
* @returns {Object}
*/
-const getInitialReportScreenParams = (reports, ignoreDefaultRooms, policies, openOnAdminRoom) => {
- const last = ReportUtils.findLastAccessedReport(reports, ignoreDefaultRooms, policies, openOnAdminRoom);
+const getInitialReportScreenParams = (reports, ignoreDefaultRooms, policies, isFirstTimeNewExpensifyUser, openOnAdminRoom) => {
+ const last = ReportUtils.findLastAccessedReport(reports, ignoreDefaultRooms, policies, isFirstTimeNewExpensifyUser, openOnAdminRoom);
// Fallback to empty if for some reason reportID cannot be derived - prevents the app from crashing
const reportID = lodashGet(last, 'reportID', '');
@@ -75,6 +80,7 @@ class MainDrawerNavigator extends Component {
props.reports,
!Permissions.canUseDefaultRooms(props.betas),
props.policies,
+ props.isFirstTimeNewExpensifyUser,
lodashGet(props, 'route.params.openOnAdminRoom', false),
);
@@ -88,9 +94,14 @@ class MainDrawerNavigator extends Component {
nextProps.reports,
!Permissions.canUseDefaultRooms(nextProps.betas),
nextProps.policies,
+ nextProps.isFirstTimeNewExpensifyUser,
lodashGet(nextProps, 'route.params.openOnAdminRoom', false),
);
if (this.initialParams.reportID === initialNextParams.reportID) {
+ // We need to wait to open the app until this check is made, since there's a race condition that can happen
+ // where OpenApp will get called beforehand, setting isFirstTimeNewExpensifyUser to false and causing us
+ // to miss the deep-linked report in ReportUtils.findLastAccessedReport
+ App.confirmReadyToOpenApp();
return false;
}
@@ -156,4 +167,7 @@ export default withOnyx({
policies: {
key: ONYXKEYS.COLLECTION.POLICY,
},
+ isFirstTimeNewExpensifyUser: {
+ key: ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER,
+ },
})(MainDrawerNavigator);
diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js
index 398cd025e598..328c1bf4c775 100644
--- a/src/libs/ReportUtils.js
+++ b/src/libs/ReportUtils.js
@@ -257,6 +257,17 @@ function isPublicRoom(report) {
return visibility === CONST.REPORT.VISIBILITY.PUBLIC || visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE;
}
+/**
+ * Whether the provided report is a public announce room
+ * @param {Object} report
+ * @param {String} report.visibility
+ * @returns {Boolean}
+ */
+function isPublicAnnounceRoom(report) {
+ const visibility = lodashGet(report, 'visibility', '');
+ return visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE;
+}
+
/**
* Get the policy type from a given report
* @param {Object} report
@@ -277,18 +288,44 @@ function hasExpensifyGuidesEmails(emails) {
return _.some(emails, email => Str.extractEmailDomain(email) === CONST.EMAIL.GUIDES_DOMAIN);
}
+/**
+ * Only returns true if this is our main 1:1 DM report with Concierge
+ *
+ * @param {Object} report
+ * @returns {Boolean}
+ */
+function isConciergeChatReport(report) {
+ return lodashGet(report, 'participants', []).length === 1
+ && report.participants[0] === CONST.EMAIL.CONCIERGE;
+}
+
/**
* @param {Record|Array<{lastReadTime, reportID}>} reports
* @param {Boolean} [ignoreDefaultRooms]
* @param {Object} policies
+ * @param {Boolean} isFirstTimeNewExpensifyUser
* @param {Boolean} openOnAdminRoom
* @returns {Object}
*/
-function findLastAccessedReport(reports, ignoreDefaultRooms, policies, openOnAdminRoom = false) {
+function findLastAccessedReport(reports, ignoreDefaultRooms, policies, isFirstTimeNewExpensifyUser, openOnAdminRoom = false) {
+ // If it's the user's first time using New Expensify, then they could either have:
+ // - just a Concierge report, if so we'll return that
+ // - their Concierge report, and a separate report that must have deeplinked them to the app before they created their account.
+ // If it's the latter, we'll use the deeplinked report over the Concierge report,
+ // since the Concierge report would be incorrectly selected over the deep-linked report in the logic below.
let sortedReports = sortReportsByLastRead(reports);
+ if (isFirstTimeNewExpensifyUser) {
+ if (sortedReports.length === 1) {
+ return sortedReports[0];
+ }
+ return _.find(sortedReports, report => !isConciergeChatReport(report));
+ }
+
if (ignoreDefaultRooms) {
- sortedReports = _.filter(sortedReports, report => !isDefaultRoom(report)
+ // We allow public announce rooms to show as the last accessed report since we bypass the default rooms beta for them.
+ // Check where ReportUtils.findLastAccessedReport is called in MainDrawerNavigator.js for more context.
+ sortedReports = _.filter(sortedReports, report => !isDefaultRoom(report) || isPublicAnnounceRoom(report)
|| getPolicyType(report, policies) === CONST.POLICY.TYPE.FREE
|| hasExpensifyGuidesEmails(lodashGet(report, ['participants'], [])));
}
@@ -419,17 +456,6 @@ function getRoomWelcomeMessage(report, policiesMap) {
return welcomeMessage;
}
-/**
- * Only returns true if this is our main 1:1 DM report with Concierge
- *
- * @param {Object} report
- * @returns {Boolean}
- */
-function isConciergeChatReport(report) {
- return lodashGet(report, 'participants', []).length === 1
- && report.participants[0] === CONST.EMAIL.CONCIERGE;
-}
-
/**
* Returns true if Concierge is one of the chat participants (1:1 as well as group chats)
* @param {Object} report
@@ -1707,7 +1733,7 @@ function canLeaveRoom(report, isPolicyMember) {
|| _.isEmpty(report.chatType)) { // DM chats don't have a chatType
return false;
}
- } else if (report.visibility === CONST.REPORT.VISIBILITY.PUBLIC_ANNOUNCE && isPolicyMember) {
+ } else if (isPublicAnnounceRoom(report) && isPolicyMember) {
return false;
}
return true;
@@ -1758,6 +1784,7 @@ export {
isArchivedRoom,
isPolicyExpenseChatAdmin,
isPublicRoom,
+ isPublicAnnounceRoom,
isConciergeChatReport,
isCurrentUserTheOnlyParticipant,
hasAutomatedExpensifyEmails,
diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js
index 30c825f40f90..2790765745be 100644
--- a/src/libs/actions/App.js
+++ b/src/libs/actions/App.js
@@ -58,6 +58,15 @@ Onyx.connect({
callback: val => preferredLocale = val,
});
+let resolveIsReadyPromise;
+const isReadyToOpenApp = new Promise((resolve) => {
+ resolveIsReadyPromise = resolve;
+});
+
+function confirmReadyToOpenApp() {
+ resolveIsReadyPromise();
+}
+
/**
* @param {Array} policies
* @return {Array} array of policy ids
@@ -128,36 +137,38 @@ AppState.addEventListener('change', (nextAppState) => {
* Fetches data needed for app initialization
*/
function openApp() {
- // We need a fresh connection/callback here to make sure that the list of policyIDs that is sent to OpenApp is the most updated list from Onyx
- const connectionID = Onyx.connect({
- key: ONYXKEYS.COLLECTION.POLICY,
- waitForCollectionCallback: true,
- callback: (policies) => {
- Onyx.disconnect(connectionID);
- API.read('OpenApp', {policyIDList: getNonOptimisticPolicyIDs(policies)}, {
- optimisticData: [
- {
- onyxMethod: CONST.ONYX.METHOD.MERGE,
- key: ONYXKEYS.IS_LOADING_REPORT_DATA,
- value: true,
- },
- ],
- successData: [
- {
- onyxMethod: CONST.ONYX.METHOD.MERGE,
- key: ONYXKEYS.IS_LOADING_REPORT_DATA,
- value: false,
- },
- ],
- failureData: [
- {
- onyxMethod: CONST.ONYX.METHOD.MERGE,
- key: ONYXKEYS.IS_LOADING_REPORT_DATA,
- value: false,
- },
- ],
- });
- },
+ isReadyToOpenApp.then(() => {
+ // We need a fresh connection/callback here to make sure that the list of policyIDs that is sent to OpenApp is the most updated list from Onyx
+ const connectionID = Onyx.connect({
+ key: ONYXKEYS.COLLECTION.POLICY,
+ waitForCollectionCallback: true,
+ callback: (policies) => {
+ Onyx.disconnect(connectionID);
+ API.read('OpenApp', {policyIDList: getNonOptimisticPolicyIDs(policies)}, {
+ optimisticData: [
+ {
+ onyxMethod: CONST.ONYX.METHOD.MERGE,
+ key: ONYXKEYS.IS_LOADING_REPORT_DATA,
+ value: true,
+ },
+ ],
+ successData: [
+ {
+ onyxMethod: CONST.ONYX.METHOD.MERGE,
+ key: ONYXKEYS.IS_LOADING_REPORT_DATA,
+ value: false,
+ },
+ ],
+ failureData: [
+ {
+ onyxMethod: CONST.ONYX.METHOD.MERGE,
+ key: ONYXKEYS.IS_LOADING_REPORT_DATA,
+ value: false,
+ },
+ ],
+ });
+ },
+ });
});
}
@@ -294,4 +305,5 @@ export {
openProfile,
openApp,
reconnectApp,
+ confirmReadyToOpenApp,
};
diff --git a/tests/actions/SessionTest.js b/tests/actions/SessionTest.js
index 62a7e183647d..2a91b0b4ad61 100644
--- a/tests/actions/SessionTest.js
+++ b/tests/actions/SessionTest.js
@@ -75,6 +75,7 @@ describe('Session', () => {
}));
// When we attempt to fetch the initial app data via the API
+ App.confirmReadyToOpenApp();
App.openApp();
return waitForPromisesToResolve();
})
diff --git a/tests/unit/NetworkTest.js b/tests/unit/NetworkTest.js
index 0f4772ad602a..a5458f356579 100644
--- a/tests/unit/NetworkTest.js
+++ b/tests/unit/NetworkTest.js
@@ -97,6 +97,7 @@ describe('NetworkTests', () => {
}));
// This should first trigger re-authentication and then a Failed to fetch
+ App.confirmReadyToOpenApp();
App.openApp();
return waitForPromisesToResolve()
.then(() => Onyx.set(ONYXKEYS.NETWORK, {isOffline: false}))