diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index eb512b7927a9..b279c8cfc6f7 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -363,7 +363,7 @@ function isUserCreatedPolicyRoom(report) { /** * Whether the provided report is a Policy Expense chat. * @param {Object} report - * @param {String} report.chatType + * @param {String} [report.chatType] * @returns {Boolean} */ function isPolicyExpenseChat(report) { diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 89324dd35485..02dd45ce7969 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -162,7 +162,7 @@ function deleteWorkspace(policyID, reports, policyName) { /** * Is the user an admin of a free policy (aka workspace)? * - * @param {Array} policies + * @param {Record} [policies] * @returns {Boolean} */ function isAdminOfFreePolicy(policies) { diff --git a/src/libs/actions/Welcome.js b/src/libs/actions/Welcome.ts similarity index 63% rename from src/libs/actions/Welcome.js rename to src/libs/actions/Welcome.ts index 8e1832edb9a7..29e0088ed689 100644 --- a/src/libs/actions/Welcome.js +++ b/src/libs/actions/Welcome.ts @@ -1,6 +1,4 @@ -import Onyx from 'react-native-onyx'; -import _ from 'underscore'; -import lodashGet from 'lodash/get'; +import Onyx, {OnyxCollection} from 'react-native-onyx'; import Navigation from '../Navigation/Navigation'; import * as ReportUtils from '../ReportUtils'; import ROUTES from '../../ROUTES'; @@ -8,15 +6,28 @@ import * as Policy from './Policy'; import ONYXKEYS from '../../ONYXKEYS'; import SCREENS from '../../SCREENS'; import CONST from '../../CONST'; +import Report from '../../types/onyx/Report'; +import OnyxPolicy from '../../types/onyx/Policy'; -let resolveIsReadyPromise; -let isReadyPromise = new Promise((resolve) => { +let resolveIsReadyPromise: (value?: Promise) => void | undefined; +let isReadyPromise = new Promise((resolve) => { resolveIsReadyPromise = resolve; }); -let isFirstTimeNewExpensifyUser; +let isFirstTimeNewExpensifyUser: boolean | undefined; let isLoadingReportData = true; -let currentUserAccountID; +let currentUserAccountID: number | undefined; + +type Route = { + name: string; + params?: {path: string; exitTo?: string; openOnAdminRoom?: boolean}; +}; + +type ShowParams = { + routes: Route[]; + showCreateMenu?: () => void; + showPopoverMenu?: () => boolean; +}; /** * Check that a few requests have completed so that the welcome action can proceed: @@ -26,22 +37,22 @@ let currentUserAccountID; * - Whether we have loaded all reports the server knows about */ function checkOnReady() { - if (!_.isBoolean(isFirstTimeNewExpensifyUser) || isLoadingReportData) { + if (isFirstTimeNewExpensifyUser === undefined || isLoadingReportData) { return; } - resolveIsReadyPromise(); + resolveIsReadyPromise?.(); } Onyx.connect({ key: ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER, initWithStoredValues: false, - callback: (val) => { + callback: (value) => { // If isFirstTimeNewExpensifyUser was true do not update it to false. We update it to false inside the Welcome.show logic // More context here https://github.com/Expensify/App/pull/16962#discussion_r1167351359 - if (!isFirstTimeNewExpensifyUser) { - isFirstTimeNewExpensifyUser = val; - } + + isFirstTimeNewExpensifyUser = value ?? undefined; + checkOnReady(); }, }); @@ -49,13 +60,13 @@ Onyx.connect({ Onyx.connect({ key: ONYXKEYS.IS_LOADING_REPORT_DATA, initWithStoredValues: false, - callback: (val) => { - isLoadingReportData = val; + callback: (value) => { + isLoadingReportData = value ?? false; checkOnReady(); }, }); -const allReports = {}; +const allReports: OnyxCollection = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, initWithStoredValues: false, @@ -68,7 +79,7 @@ Onyx.connect({ }, }); -const allPolicies = {}; +const allPolicies: OnyxCollection = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY, callback: (val, key) => { @@ -98,13 +109,8 @@ Onyx.connect({ /** * Shows a welcome action on first login - * - * @param {Object} params - * @param {Object} params.routes - * @param {Function} [params.showCreateMenu] - * @param {Function} [params.showPopoverMenu] */ -function show({routes, showCreateMenu = () => {}, showPopoverMenu = () => {}}) { +function show({routes, showCreateMenu = () => {}, showPopoverMenu = () => false}: ShowParams) { isReadyPromise.then(() => { if (!isFirstTimeNewExpensifyUser) { return; @@ -112,33 +118,37 @@ function show({routes, showCreateMenu = () => {}, showPopoverMenu = () => {}}) { // If we are rendering the SidebarScreen at the same time as a workspace route that means we've already created a workspace via workspace/new and should not open the global // create menu right now. We should also stay on the workspace page if that is our destination. - const topRoute = _.last(routes); - const isWorkspaceRoute = topRoute.name === 'Settings' && topRoute.params.path.includes('workspace'); - const transitionRoute = _.find(routes, (route) => route.name === SCREENS.TRANSITION_BETWEEN_APPS); - const exitingToWorkspaceRoute = lodashGet(transitionRoute, 'params.exitTo', '') === 'workspace/new'; - const openOnAdminRoom = lodashGet(topRoute, 'params.openOnAdminRoom', false); - const isDisplayingWorkspaceRoute = isWorkspaceRoute || exitingToWorkspaceRoute; + const topRoute = routes.length > 0 ? routes[routes.length - 1] : undefined; + const isWorkspaceRoute = topRoute !== undefined && topRoute.name === 'Settings' && topRoute.params?.path.includes('workspace'); + const transitionRoute = routes.find((route) => route.name === SCREENS.TRANSITION_BETWEEN_APPS); + const exitingToWorkspaceRoute = transitionRoute?.params?.exitTo === 'workspace/new'; + const openOnAdminRoom = topRoute?.params?.openOnAdminRoom ?? false; + const isDisplayingWorkspaceRoute = isWorkspaceRoute ?? exitingToWorkspaceRoute; // If we already opened the workspace settings or want the admin room to stay open, do not // navigate away to the workspace chat report const shouldNavigateToWorkspaceChat = !isDisplayingWorkspaceRoute && !openOnAdminRoom; - const workspaceChatReport = _.find( - allReports, - (report) => ReportUtils.isPolicyExpenseChat(report) && report.ownerAccountID === currentUserAccountID && report.statusNum !== CONST.REPORT.STATUS.CLOSED, - ); + const workspaceChatReport = Object.values(allReports ?? {}).find((report) => { + if (report) { + return ReportUtils.isPolicyExpenseChat(report) && report.ownerAccountID === currentUserAccountID && report.statusNum !== CONST.REPORT.STATUS.CLOSED; + } + return false; + }); - if (workspaceChatReport || openOnAdminRoom) { + if (workspaceChatReport ?? openOnAdminRoom) { // This key is only updated when we call ReconnectApp, setting it to false now allows the user to navigate normally instead of always redirecting to the workspace chat Onyx.set(ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER, false); } if (shouldNavigateToWorkspaceChat && workspaceChatReport) { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(workspaceChatReport.reportID)); + if (workspaceChatReport.reportID !== null) { + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(workspaceChatReport.reportID)); + } // If showPopoverMenu exists and returns true then it opened the Popover Menu successfully, and we can update isFirstTimeNewExpensifyUser // so the Welcome logic doesn't run again - if (showPopoverMenu()) { + if (showPopoverMenu?.()) { isFirstTimeNewExpensifyUser = false; } @@ -147,7 +157,7 @@ function show({routes, showCreateMenu = () => {}, showPopoverMenu = () => {}}) { // If user is not already an admin of a free policy and we are not navigating them to their workspace or creating a new workspace via workspace/new then // we will show the create menu. - if (!Policy.isAdminOfFreePolicy(allPolicies) && !isDisplayingWorkspaceRoute) { + if (!Policy.isAdminOfFreePolicy(allPolicies ?? undefined) && !isDisplayingWorkspaceRoute) { showCreateMenu(); } @@ -164,7 +174,7 @@ function resetReadyCheck() { isLoadingReportData = true; } -function serverDataIsReadyPromise() { +function serverDataIsReadyPromise(): Promise { return isReadyPromise; }