Skip to content

Commit

Permalink
Merge pull request #18128 from Expensify/OSBotify-cherry-pick-staging…
Browse files Browse the repository at this point in the history
…-18114

🍒 Cherry pick PR #18114 to staging 🍒
  • Loading branch information
OSBotify authored Apr 28, 2023
2 parents 59fa578 + e8a9c08 commit 0efba0e
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 53 deletions.
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.3.7.2</string>
<string>1.3.7.3</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensifyTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.3.7.2</string>
<string>1.3.7.3</string>
</dict>
</plist>
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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.",
Expand Down
18 changes: 16 additions & 2 deletions src/libs/Navigation/AppNavigator/MainDrawerNavigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -35,6 +36,8 @@ const propTypes = {
type: PropTypes.string,
})),

isFirstTimeNewExpensifyUser: PropTypes.bool,

route: PropTypes.shape({
params: PropTypes.shape({
openOnAdminRoom: PropTypes.bool,
Expand All @@ -48,6 +51,7 @@ const defaultProps = {
reports: {},
betas: [],
policies: {},
isFirstTimeNewExpensifyUser: false,
};

/**
Expand All @@ -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', '');
Expand All @@ -75,6 +80,7 @@ class MainDrawerNavigator extends Component {
props.reports,
!Permissions.canUseDefaultRooms(props.betas),
props.policies,
props.isFirstTimeNewExpensifyUser,
lodashGet(props, 'route.params.openOnAdminRoom', false),
);

Expand All @@ -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;
}

Expand Down Expand Up @@ -156,4 +167,7 @@ export default withOnyx({
policies: {
key: ONYXKEYS.COLLECTION.POLICY,
},
isFirstTimeNewExpensifyUser: {
key: ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER,
},
})(MainDrawerNavigator);
55 changes: 41 additions & 14 deletions src/libs/ReportUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<String, {lastReadTime, reportID}>|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'], [])));
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1758,6 +1784,7 @@ export {
isArchivedRoom,
isPolicyExpenseChatAdmin,
isPublicRoom,
isPublicAnnounceRoom,
isConciergeChatReport,
isCurrentUserTheOnlyParticipant,
hasAutomatedExpensifyEmails,
Expand Down
72 changes: 42 additions & 30 deletions src/libs/actions/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>} array of policy ids
Expand Down Expand Up @@ -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,
},
],
});
},
});
});
}

Expand Down Expand Up @@ -294,4 +305,5 @@ export {
openProfile,
openApp,
reconnectApp,
confirmReadyToOpenApp,
};
1 change: 1 addition & 0 deletions tests/actions/SessionTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ describe('Session', () => {
}));

// When we attempt to fetch the initial app data via the API
App.confirmReadyToOpenApp();
App.openApp();
return waitForPromisesToResolve();
})
Expand Down
1 change: 1 addition & 0 deletions tests/unit/NetworkTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}))
Expand Down

0 comments on commit 0efba0e

Please sign in to comment.