From 047ece7dc40199eae920c5769a807eeded3ac5f1 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 11 Mar 2025 09:36:35 +0100 Subject: [PATCH 1/9] Remove reportID param from dismissModal function --- contributingGuides/NAVIGATION.md | 2 +- .../GetStateForActionHandlers.ts | 26 +++++++- .../RootStackRouter.ts | 19 +++++- .../createRootStackNavigator/types.ts | 3 + src/libs/Navigation/Navigation.ts | 42 +++++++++---- src/libs/actions/IOU.ts | 60 +++++++++++++++---- src/libs/actions/Report.ts | 10 +++- src/libs/actions/Task.ts | 2 +- src/libs/actions/TeachersUnite.ts | 4 +- src/pages/AddPersonalBankAccountPage.tsx | 2 +- .../AddBankAccount/AddBankAccount.tsx | 2 +- src/pages/NewChatPage.tsx | 2 +- src/pages/RoomInvitePage.tsx | 2 +- .../TransactionDuplicate/Confirmation.tsx | 2 +- src/pages/TransactionReceiptPage.tsx | 2 +- src/pages/tasks/TaskAssigneeSelectorModal.tsx | 4 +- src/pages/tasks/TaskDescriptionPage.tsx | 4 +- src/pages/tasks/TaskTitlePage.tsx | 4 +- src/pages/workspace/WorkspaceNewRoomPage.tsx | 2 +- .../workspace/WorkspaceOverviewSharePage.tsx | 2 +- 20 files changed, 152 insertions(+), 44 deletions(-) diff --git a/contributingGuides/NAVIGATION.md b/contributingGuides/NAVIGATION.md index f0db6723b4e5c..20d284b8e5a71 100644 --- a/contributingGuides/NAVIGATION.md +++ b/contributingGuides/NAVIGATION.md @@ -34,7 +34,7 @@ When creating RHP flows, you have to remember a couple of things: - We use a custom `goBack` function to handle the browser and the `react-navigation` history stack. Under the hood, it resolves to either replacing the current screen with the one we navigate to (deeplinking scenario) or just going back if we reached the current page by navigating in App (pops the screen). It ensures the requested behaviors on web, which is navigating back to the place from where you deeplinked when going into the RHP flow by it. -- If you want to navigate to a certain report after completing a flow related to it, e.g. `RequestMoney` flow with a certain group/user, you should use `Navigation.dismissModal` with this `reportID` as an argument. If, in the future, we would like to navigate to something different than the report after such flows, the API should be rather easy to change. We do it like that in order to replace the RHP flow with the new report instead of pushing it, so pressing the back button does not navigate back to the ending page of the flow. If we were to navigate to the same report, we just pop the RHP modal. +- If you want to navigate to a certain report after completing a flow related to it, e.g. `RequestMoney` flow with a certain group/user, you should use `Navigation.dismissModalWithReport` with this `reportID` as an argument. If, in the future, we would like to navigate to something different than the report after such flows, the API should be rather easy to change. We do it like that in order to replace the RHP flow with the new report instead of pushing it, so pressing the back button does not navigate back to the ending page of the flow. If we were to navigate to the same report, we just pop the RHP modal. ### Example of usage diff --git a/src/libs/Navigation/AppNavigator/createRootStackNavigator/GetStateForActionHandlers.ts b/src/libs/Navigation/AppNavigator/createRootStackNavigator/GetStateForActionHandlers.ts index bb796c74eee18..1965d7a1bc0c9 100644 --- a/src/libs/Navigation/AppNavigator/createRootStackNavigator/GetStateForActionHandlers.ts +++ b/src/libs/Navigation/AppNavigator/createRootStackNavigator/GetStateForActionHandlers.ts @@ -7,7 +7,7 @@ import type {RootNavigatorParamList, State} from '@libs/Navigation/types'; import * as SearchQueryUtils from '@libs/SearchQueryUtils'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; -import type {OpenWorkspaceSplitActionType, PushActionType, SwitchPolicyIdActionType} from './types'; +import type {OpenWorkspaceSplitActionType, PushActionType, ReplaceActionType, SwitchPolicyIdActionType} from './types'; const MODAL_ROUTES_TO_DISMISS: string[] = [ NAVIGATORS.WORKSPACE_SPLIT_NAVIGATOR, @@ -237,6 +237,29 @@ function handlePushSearchPageAction( return stackRouter.getStateForAction(state, updatedAction, configOptions); } +function handleReplaceReportsSplitNavigatorAction( + state: StackNavigationState, + action: ReplaceActionType, + configOptions: RouterConfigOptions, + stackRouter: Router, CommonActions.Action | StackActionType>, +) { + const stateWithReportsSplitNavigator = stackRouter.getStateForAction(state, action, configOptions); + + if (!stateWithReportsSplitNavigator) { + Log.hmmm('[handleReplaceReportsSplitNavigatorAction] ReportsSplitNavigator has not been found in the navigation state.'); + return null; + } + + const lastReportsSplitNavigator = stateWithReportsSplitNavigator.routes.at(-1); + + // ReportScreen should always be opened with an animation when replacing the navigator + if (lastReportsSplitNavigator?.key) { + reportsSplitsWithEnteringAnimation.add(lastReportsSplitNavigator.key); + } + + return stateWithReportsSplitNavigator; +} + /** * Handles the DISMISS_MODAL action. * If the last route is a modal route, it has to be popped from the navigation stack. @@ -275,6 +298,7 @@ export { handleDismissModalAction, handlePushReportSplitAction, handlePushSearchPageAction, + handleReplaceReportsSplitNavigatorAction, handleSwitchPolicyIDAction, handleSwitchPolicyIDFromSearchAction, handleNavigatingToModalFromModal, diff --git a/src/libs/Navigation/AppNavigator/createRootStackNavigator/RootStackRouter.ts b/src/libs/Navigation/AppNavigator/createRootStackNavigator/RootStackRouter.ts index fcaad4ae232a4..0e9b4b2c36692 100644 --- a/src/libs/Navigation/AppNavigator/createRootStackNavigator/RootStackRouter.ts +++ b/src/libs/Navigation/AppNavigator/createRootStackNavigator/RootStackRouter.ts @@ -14,10 +14,19 @@ import { handleOpenWorkspaceSplitAction, handlePushReportSplitAction, handlePushSearchPageAction, + handleReplaceReportsSplitNavigatorAction, handleSwitchPolicyIDAction, } from './GetStateForActionHandlers'; import syncBrowserHistory from './syncBrowserHistory'; -import type {DismissModalActionType, OpenWorkspaceSplitActionType, PushActionType, RootStackNavigatorAction, RootStackNavigatorRouterOptions, SwitchPolicyIdActionType} from './types'; +import type { + DismissModalActionType, + OpenWorkspaceSplitActionType, + PushActionType, + ReplaceActionType, + RootStackNavigatorAction, + RootStackNavigatorRouterOptions, + SwitchPolicyIdActionType, +} from './types'; function isOpenWorkspaceSplitAction(action: RootStackNavigatorAction): action is OpenWorkspaceSplitActionType { return action.type === CONST.NAVIGATION.ACTION_TYPE.OPEN_WORKSPACE_SPLIT; @@ -31,6 +40,10 @@ function isPushAction(action: RootStackNavigatorAction): action is PushActionTyp return action.type === CONST.NAVIGATION.ACTION_TYPE.PUSH; } +function isReplaceAction(action: RootStackNavigatorAction): action is ReplaceActionType { + return action.type === CONST.NAVIGATION.ACTION_TYPE.REPLACE; +} + function isDismissModalAction(action: RootStackNavigatorAction): action is DismissModalActionType { return action.type === CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL; } @@ -82,6 +95,10 @@ function RootStackRouter(options: RootStackNavigatorRouterOptions) { return handleDismissModalAction(state, configOptions, stackRouter); } + if (isReplaceAction(action) && action.payload.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { + return handleReplaceReportsSplitNavigatorAction(state, action, configOptions, stackRouter); + } + if (isPushAction(action)) { if (action.payload.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR) { return handlePushReportSplitAction(state, action, configOptions, stackRouter, setActiveWorkspaceID); diff --git a/src/libs/Navigation/AppNavigator/createRootStackNavigator/types.ts b/src/libs/Navigation/AppNavigator/createRootStackNavigator/types.ts index 6dae82db35b5b..67d69f90a2056 100644 --- a/src/libs/Navigation/AppNavigator/createRootStackNavigator/types.ts +++ b/src/libs/Navigation/AppNavigator/createRootStackNavigator/types.ts @@ -29,6 +29,8 @@ type SwitchPolicyIdActionType = RootStackNavigatorActionType & { type PushActionType = StackActionType & {type: typeof CONST.NAVIGATION.ACTION_TYPE.PUSH}; +type ReplaceActionType = StackActionType & {type: typeof CONST.NAVIGATION.ACTION_TYPE.REPLACE}; + type DismissModalActionType = RootStackNavigatorActionType & { type: typeof CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL; }; @@ -49,6 +51,7 @@ export type { OpenWorkspaceSplitActionType, SwitchPolicyIdActionType, PushActionType, + ReplaceActionType, DismissModalActionType, RootStackNavigatorAction, RootStackNavigatorActionType, diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 282dda5d3c57a..7b956bc73dcbc 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -24,6 +24,7 @@ import originalCloseRHPFlow from './helpers/closeRHPFlow'; import getPolicyIDFromState from './helpers/getPolicyIDFromState'; import getStateFromPath from './helpers/getStateFromPath'; import getTopmostReportParams from './helpers/getTopmostReportParams'; +import {isFullScreenName} from './helpers/isNavigatorName'; import isReportOpenInRHP from './helpers/isReportOpenInRHP'; import isSideModalNavigator from './helpers/isSideModalNavigator'; import linkTo from './helpers/linkTo'; @@ -469,20 +470,20 @@ function waitForProtectedRoutes() { }); } -type NavigateToReportWithPolicyCheckPayload = {report?: OnyxEntry; reportID?: string; reportActionID?: string; referrer?: string; policyIDToCheck?: string}; +type NavigateToReportWithPolicyCheckPayload = {report?: OnyxEntry; reportID?: string; reportActionID?: string; referrer?: string; policyIDToCheck?: string; forceReplace?: boolean}; /** * Navigates to a report passed as a param (as an id or report object) and checks whether the target object belongs to the currently selected workspace. * If not, the current workspace is set to global. */ -function navigateToReportWithPolicyCheck({report, reportID, reportActionID, referrer, policyIDToCheck}: NavigateToReportWithPolicyCheckPayload, ref = navigationRef) { +function navigateToReportWithPolicyCheck({report, reportID, reportActionID, referrer, policyIDToCheck}: NavigateToReportWithPolicyCheckPayload, forceReplace = false, ref = navigationRef) { const targetReport = reportID ? {reportID, ...allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`]} : report; const policyID = policyIDToCheck ?? getPolicyIDFromState(navigationRef.getRootState() as State); const policyMemberAccountIDs = getPolicyEmployeeAccountIDs(policyID); const shouldOpenAllWorkspace = isEmptyObject(targetReport) ? true : !doesReportBelongToWorkspace(targetReport, policyMemberAccountIDs, policyID); if ((shouldOpenAllWorkspace && !policyID) || !shouldOpenAllWorkspace) { - linkTo(ref.current, ROUTES.REPORT_WITH_ID.getRoute(targetReport?.reportID, reportActionID, referrer)); + linkTo(ref.current, ROUTES.REPORT_WITH_ID.getRoute(targetReport?.reportID, reportActionID, referrer), {forceReplace: !!forceReplace}); return; } @@ -498,6 +499,17 @@ function navigateToReportWithPolicyCheck({report, reportID, reportActionID, refe params.referrer = referrer; } + if (forceReplace) { + ref.dispatch( + StackActions.replace(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, { + policyID: undefined, + screen: SCREENS.REPORT, + params, + }), + ); + return; + } + ref.dispatch( StackActions.push(NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, { policyID: undefined, @@ -528,23 +540,31 @@ function getReportRouteByID(reportID?: string, routes: NavigationRoute[] = navig /** * Closes the modal navigator (RHP, LHP, onboarding). */ -const dismissModal = (reportID?: string, ref = navigationRef) => { +const dismissModal = (ref = navigationRef) => { isNavigationReady().then(() => { ref.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL}); - if (!reportID) { - return; - } - navigateToReportWithPolicyCheck({reportID}); }); }; /** * Dismisses the modal and opens the given report. */ -const dismissModalWithReport = (report: OnyxEntry, ref = navigationRef) => { +const dismissModalWithReport = (navigateToReportPayload: NavigateToReportWithPolicyCheckPayload, ref = navigationRef) => { isNavigationReady().then(() => { - ref.dispatch({type: CONST.NAVIGATION.ACTION_TYPE.DISMISS_MODAL}); - navigateToReportWithPolicyCheck({report}); + if (getIsNarrowLayout()) { + const topmostReportID = getTopmostReportId(); + const areReportsIDsDefined = !!topmostReportID && !!navigateToReportPayload.reportID; + const isReportsSplitTopmostFullScreen = ref.getRootState().routes.findLast((route) => isFullScreenName(route.name))?.name === NAVIGATORS.REPORTS_SPLIT_NAVIGATOR; + if (topmostReportID === navigateToReportPayload.reportID && areReportsIDsDefined && isReportsSplitTopmostFullScreen) { + dismissModal(); + return; + } + const forceReplace = true; + navigateToReportWithPolicyCheck(navigateToReportPayload, forceReplace); + return; + } + dismissModal(); + navigateToReportWithPolicyCheck(navigateToReportPayload); }); }; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 9029f272122b9..808977883005d 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4758,7 +4758,11 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation) { } InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : activeReportID); + if (isSearchTopmostFullScreenRoute()) { + Navigation.dismissModal(); + } else { + Navigation.dismissModalWithReport({reportID: activeReportID}); + } const trackReport = Navigation.getReportRouteByID(linkedTrackedExpenseReportAction?.childReportID); if (trackReport?.key) { @@ -4842,7 +4846,12 @@ function submitPerDiemExpense(submitPerDiemExpenseInformation: PerDiemExpenseInf API.write(WRITE_COMMANDS.CREATE_PER_DIEM_REQUEST, parameters, onyxData); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : activeReportID); + if (isSearchTopmostFullScreenRoute()) { + Navigation.dismissModal(); + } else { + Navigation.dismissModalWithReport({reportID: activeReportID}); + } + if (activeReportID) { notifyNewAction(activeReportID, payeeAccountID); } @@ -4909,7 +4918,7 @@ function sendInvoice( if (isSearchTopmostFullScreenRoute()) { Navigation.dismissModal(); } else { - Navigation.dismissModalWithReport(invoiceRoom); + Navigation.dismissModalWithReport({report: invoiceRoom}); } notifyNewAction(invoiceRoom.reportID, receiver.accountID); @@ -5135,7 +5144,11 @@ function trackExpense(params: CreateTrackExpenseParams) { } } InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : activeReportID); + if (isSearchTopmostFullScreenRoute()) { + Navigation.dismissModal(); + } else { + Navigation.dismissModalWithReport({reportID: activeReportID}); + } if (action === CONST.IOU.ACTION.SHARE) { if (isSearchTopmostFullScreenRoute() && activeReportID) { @@ -5718,7 +5731,12 @@ function splitBill({ API.write(WRITE_COMMANDS.SPLIT_BILL, parameters, onyxData); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : existingSplitChatReportID); + if (isSearchTopmostFullScreenRoute()) { + Navigation.dismissModal(); + } else { + Navigation.dismissModalWithReport({reportID: existingSplitChatReportID}); + } + notifyNewAction(splitData.chatReportID, currentUserAccountID); } @@ -5791,7 +5809,11 @@ function splitBillAndOpenReport({ API.write(WRITE_COMMANDS.SPLIT_BILL_AND_OPEN_REPORT, parameters, onyxData); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : splitData.chatReportID); + if (isSearchTopmostFullScreenRoute()) { + Navigation.dismissModal(); + } else { + Navigation.dismissModalWithReport({reportID: splitData.chatReportID}); + } notifyNewAction(splitData.chatReportID, currentUserAccountID); } @@ -6110,7 +6132,7 @@ function startSplitBill({ API.write(WRITE_COMMANDS.START_SPLIT_BILL, parameters, {optimisticData, successData, failureData}); - Navigation.dismissModalWithReport(splitChatReport); + Navigation.dismissModalWithReport({report: splitChatReport}); notifyNewAction(splitChatReport.reportID, currentUserAccountID); } @@ -6372,7 +6394,11 @@ function completeSplitBill( API.write(WRITE_COMMANDS.COMPLETE_SPLIT_BILL, parameters, {optimisticData, successData, failureData}); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : chatReportID); + if (isSearchTopmostFullScreenRoute()) { + Navigation.dismissModal(); + } else { + Navigation.dismissModalWithReport({reportID: chatReportID}); + } notifyNewAction(chatReportID, sessionAccountID); } @@ -6555,7 +6581,11 @@ function createDistanceRequest(distanceRequestInformation: CreateDistanceRequest API.write(WRITE_COMMANDS.CREATE_DISTANCE_REQUEST, parameters, onyxData); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); const activeReportID = isMoneyRequestReport && report?.reportID ? report.reportID : parameters.chatReportID; - Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : activeReportID); + if (isSearchTopmostFullScreenRoute()) { + Navigation.dismissModal(); + } else { + Navigation.dismissModalWithReport({reportID: activeReportID}); + } notifyNewAction(activeReportID, userAccountID); } @@ -8256,7 +8286,11 @@ function sendMoneyElsewhere(report: OnyxEntry, amount: number, API.write(WRITE_COMMANDS.SEND_MONEY_ELSEWHERE, params, {optimisticData, successData, failureData}); - Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : params.chatReportID); + if (isSearchTopmostFullScreenRoute()) { + Navigation.dismissModal(); + } else { + Navigation.dismissModalWithReport({reportID: params.chatReportID}); + } notifyNewAction(params.chatReportID, managerID); } @@ -8269,7 +8303,11 @@ function sendMoneyWithWallet(report: OnyxEntry, amount: number API.write(WRITE_COMMANDS.SEND_MONEY_WITH_WALLET, params, {optimisticData, successData, failureData}); - Navigation.dismissModal(isSearchTopmostFullScreenRoute() ? undefined : params.chatReportID); + if (isSearchTopmostFullScreenRoute()) { + Navigation.dismissModal(); + } else { + Navigation.dismissModalWithReport({reportID: params.chatReportID}); + } notifyNewAction(params.chatReportID, managerID); } diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 0b7fa684de20c..cf638597ad04f 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -66,6 +66,7 @@ import type EnvironmentType from '@libs/Environment/getEnvironment/types'; import * as ErrorUtils from '@libs/ErrorUtils'; import {getMicroSecondOnyxErrorWithTranslationKey} from '@libs/ErrorUtils'; import fileDownload from '@libs/fileDownload'; +import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import HttpUtils from '@libs/HttpUtils'; import isPublicScreenRoute from '@libs/isPublicScreenRoute'; import * as Localize from '@libs/Localize'; @@ -1200,6 +1201,11 @@ function navigateToAndOpenReport( // We want to pass newChat here because if anything is passed in that param (even an existing chat), we will try to create a chat on the server openReport(report?.reportID, '', userLogins, newChat, undefined, undefined, undefined, avatarFile); if (shouldDismissModal) { + if (getIsNarrowLayout()) { + Navigation.dismissModalWithReport({report}); + return; + } + Navigation.dismissModal(); } @@ -2400,7 +2406,7 @@ function navigateToConciergeChat(shouldDismissModal = false, checkIfCurrentPageA navigateToAndOpenReport([CONST.EMAIL.CONCIERGE], shouldDismissModal); }); } else if (shouldDismissModal) { - Navigation.dismissModal(conciergeChatReportID); + Navigation.dismissModalWithReport({reportID: conciergeChatReportID}); } else { Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(conciergeChatReportID), linkToOptions); } @@ -2656,7 +2662,7 @@ function addPolicyReport(policyReport: OptimisticChatReport) { }; API.write(WRITE_COMMANDS.ADD_WORKSPACE_ROOM, parameters, {optimisticData, successData, failureData}); - Navigation.dismissModalWithReport(policyReport); + Navigation.dismissModalWithReport({report: policyReport}); } /** Deletes a report, along with its reportActions, any linked reports, and any linked IOU report. */ diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts index 9045b11234512..a208893e89f30 100644 --- a/src/libs/actions/Task.ts +++ b/src/libs/actions/Task.ts @@ -340,7 +340,7 @@ function createTaskAndNavigate( InteractionManager.runAfterInteractions(() => { clearOutTaskInfo(); }); - Navigation.dismissModal(parentReportID); + Navigation.dismissModalWithReport({reportID: parentReportID}); } notifyNewAction(parentReportID, currentUserAccountID); } diff --git a/src/libs/actions/TeachersUnite.ts b/src/libs/actions/TeachersUnite.ts index 11cb189b20a7b..ed78a7c60ad84 100644 --- a/src/libs/actions/TeachersUnite.ts +++ b/src/libs/actions/TeachersUnite.ts @@ -74,7 +74,7 @@ function referTeachersUniteVolunteer(partnerUserID: string, firstName: string, l }; API.write(WRITE_COMMANDS.REFER_TEACHERS_UNITE_VOLUNTEER, parameters, {optimisticData}); - Navigation.dismissModal(publicRoomReportID); + Navigation.dismissModalWithReport({reportID: publicRoomReportID}); } /** @@ -206,7 +206,7 @@ function addSchoolPrincipal(firstName: string, partnerUserID: string, lastName: }; API.write(WRITE_COMMANDS.ADD_SCHOOL_PRINCIPAL, parameters, {optimisticData, successData, failureData}); - Navigation.dismissModal(expenseChatReportID); + Navigation.dismissModalWithReport({reportID: expenseChatReportID}); } export default {referTeachersUniteVolunteer, addSchoolPrincipal}; diff --git a/src/pages/AddPersonalBankAccountPage.tsx b/src/pages/AddPersonalBankAccountPage.tsx index 07da0d48c2498..0734a5749f4c9 100644 --- a/src/pages/AddPersonalBankAccountPage.tsx +++ b/src/pages/AddPersonalBankAccountPage.tsx @@ -66,7 +66,7 @@ function AddPersonalBankAccountPage() { const onSuccessFallbackRoute = personalBankAccount?.onSuccessFallbackRoute ?? ''; if (exitReportID) { - Navigation.dismissModal(exitReportID); + Navigation.dismissModalWithReport({reportID: exitReportID}); } else if (shouldContinue && onSuccessFallbackRoute) { continueSetup(onSuccessFallbackRoute); } else { diff --git a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx index a273b210efa98..7bb194b07b481 100644 --- a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx +++ b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx @@ -45,7 +45,7 @@ function AddBankAccount() { const onSuccessFallbackRoute = personalBankAccount?.onSuccessFallbackRoute ?? ''; if (exitReportID) { - Navigation.dismissModal(exitReportID); + Navigation.dismissModalWithReport({reportID: exitReportID}); return; } if (shouldContinue && onSuccessFallbackRoute) { diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index 6c14fcc0d2376..d1bc834c108d7 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -229,7 +229,7 @@ function NewChatPage() { const selectOption = useCallback( (option?: Option) => { if (option?.isSelfDM) { - Navigation.dismissModal(option.reportID); + Navigation.dismissModalWithReport({reportID: option.reportID}); return; } if (selectedOptions.length && option) { diff --git a/src/pages/RoomInvitePage.tsx b/src/pages/RoomInvitePage.tsx index a212d1ab5c49b..eae5be29c9d71 100644 --- a/src/pages/RoomInvitePage.tsx +++ b/src/pages/RoomInvitePage.tsx @@ -215,7 +215,7 @@ function RoomInvitePage({ const goBack = useCallback(() => { if (role === CONST.IOU.SHARE.ROLE.ACCOUNTANT) { - Navigation.dismissModal(reportID); + Navigation.dismissModalWithReport({reportID}); return; } Navigation.goBack(backRoute); diff --git a/src/pages/TransactionDuplicate/Confirmation.tsx b/src/pages/TransactionDuplicate/Confirmation.tsx index 805fda5c298af..0e9f7a86077d4 100644 --- a/src/pages/TransactionDuplicate/Confirmation.tsx +++ b/src/pages/TransactionDuplicate/Confirmation.tsx @@ -66,7 +66,7 @@ function Confirmation() { const resolveDuplicates = useCallback(() => { IOU.resolveDuplicates(transactionsMergeParams); - Navigation.dismissModal(reportAction?.childReportID); + Navigation.dismissModalWithReport({reportID: reportAction?.childReportID}); }, [transactionsMergeParams, reportAction?.childReportID]); const contextValue = useMemo( diff --git a/src/pages/TransactionReceiptPage.tsx b/src/pages/TransactionReceiptPage.tsx index 132d1607fb52c..abda0014c792d 100644 --- a/src/pages/TransactionReceiptPage.tsx +++ b/src/pages/TransactionReceiptPage.tsx @@ -59,7 +59,7 @@ function TransactionReceipt({route}: TransactionReceiptProps) { Navigation.dismissModal(); } else { const isOneTransactionThread = isOneTransactionThreadReportUtils(report?.reportID, report?.parentReportID, parentReportAction); - Navigation.dismissModal(isOneTransactionThread ? report?.parentReportID : report?.reportID); + Navigation.dismissModalWithReport({reportID: isOneTransactionThread ? report?.parentReportID : report?.reportID}); } }; diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.tsx b/src/pages/tasks/TaskAssigneeSelectorModal.tsx index 5aaf02d8ba3e6..fbfefaefec8c3 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.tsx +++ b/src/pages/tasks/TaskAssigneeSelectorModal.tsx @@ -106,7 +106,7 @@ function TaskAssigneeSelectorModal() { const reportOnyx = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${route.params?.reportID}`]; if (reportOnyx && !ReportUtils.isTaskReport(reportOnyx)) { Navigation.isNavigationReady().then(() => { - Navigation.dismissModal(reportOnyx.reportID); + Navigation.dismissModalWithReport({reportID: reportOnyx.reportID}); }); } return reports?.[`${ONYXKEYS.COLLECTION.REPORT}${route.params?.reportID}`]; @@ -178,7 +178,7 @@ function TaskAssigneeSelectorModal() { TaskActions.editTaskAssignee(report, session?.accountID ?? -1, option?.login ?? '', option?.accountID, assigneeChatReport); } InteractionManager.runAfterInteractions(() => { - Navigation.dismissModal(report.reportID); + Navigation.dismissModalWithReport({reportID: report?.reportID}); }); // If there's no report, we're creating a new task } else if (option.accountID) { diff --git a/src/pages/tasks/TaskDescriptionPage.tsx b/src/pages/tasks/TaskDescriptionPage.tsx index 9fdf1757ca96f..d855228e3c970 100644 --- a/src/pages/tasks/TaskDescriptionPage.tsx +++ b/src/pages/tasks/TaskDescriptionPage.tsx @@ -59,14 +59,14 @@ function TaskDescriptionPage({report, currentUserPersonalDetails}: TaskDescripti editTask(report, {description: values.description}); } - Navigation.dismissModal(report?.reportID); + Navigation.dismissModalWithReport({reportID: report?.reportID}); }, [report], ); if (!isTaskReport(report)) { Navigation.isNavigationReady().then(() => { - Navigation.dismissModal(report?.reportID); + Navigation.dismissModalWithReport({reportID: report?.reportID}); }); } const inputRef = useRef(null); diff --git a/src/pages/tasks/TaskTitlePage.tsx b/src/pages/tasks/TaskTitlePage.tsx index 30beb0bd700d6..8d2f33d2cd75d 100644 --- a/src/pages/tasks/TaskTitlePage.tsx +++ b/src/pages/tasks/TaskTitlePage.tsx @@ -63,14 +63,14 @@ function TaskTitlePage({report, currentUserPersonalDetails}: TaskTitlePageProps) editTask(report, {title: values.title}); } - Navigation.dismissModal(report?.reportID); + Navigation.dismissModalWithReport({reportID: report?.reportID}); }, [report], ); if (!isTaskReport(report)) { Navigation.isNavigationReady().then(() => { - Navigation.dismissModal(report?.reportID); + Navigation.dismissModalWithReport({reportID: report?.reportID}); }); } diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 52f687c43d81a..1d665d59af535 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -132,7 +132,7 @@ function WorkspaceNewRoomPage() { if (!(((wasLoading && !isLoading) || (isOffline && isLoading)) && isEmptyObject(errorFields))) { return; } - Navigation.dismissModal(newRoomReportID); + Navigation.dismissModalWithReport({reportID: newRoomReportID}); // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps -- we just want this to update on changing the form State }, [isLoading, errorFields]); diff --git a/src/pages/workspace/WorkspaceOverviewSharePage.tsx b/src/pages/workspace/WorkspaceOverviewSharePage.tsx index 2eab58a65e78d..a01acab815421 100644 --- a/src/pages/workspace/WorkspaceOverviewSharePage.tsx +++ b/src/pages/workspace/WorkspaceOverviewSharePage.tsx @@ -89,7 +89,7 @@ function WorkspaceOverviewSharePage({policy}: WithPolicyProps) { if (!adminRoom?.reportID) { return; } - Navigation.dismissModal(adminRoom.reportID); + Navigation.dismissModalWithReport({reportID: adminRoom.reportID}); }} > {CONST.REPORT.WORKSPACE_CHAT_ROOMS.ADMINS} From ce036e69f875ae873f01455beec64e35880899e4 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 11 Mar 2025 09:51:32 +0100 Subject: [PATCH 2/9] Fix issue: Workspace-Overview page is shown briefly before landing on memebers page when inviting a user --- src/pages/workspace/WorkspaceInviteMessagePage.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.tsx b/src/pages/workspace/WorkspaceInviteMessagePage.tsx index 3f48e3c7a2f96..458395e47dbf9 100644 --- a/src/pages/workspace/WorkspaceInviteMessagePage.tsx +++ b/src/pages/workspace/WorkspaceInviteMessagePage.tsx @@ -24,6 +24,7 @@ import {clearDraftValues} from '@libs/actions/FormActions'; import {openExternalLink} from '@libs/actions/Link'; import {addMembersToWorkspace} from '@libs/actions/Policy/Member'; import {setWorkspaceInviteMessageDraft} from '@libs/actions/Policy/Policy'; +import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import {getAvatarsForAccountIDs} from '@libs/OptionsListUtils'; @@ -112,6 +113,12 @@ function WorkspaceInviteMessagePage({policy, route, currentUserPersonalDetails}: Navigation.setNavigationActionToMicrotaskQueue(() => Navigation.dismissModal()); return; } + + if (getIsNarrowLayout()) { + Navigation.navigate(ROUTES.WORKSPACE_MEMBERS.getRoute(route.params.policyID), {forceReplace: true}); + return; + } + Navigation.setNavigationActionToMicrotaskQueue(() => { Navigation.dismissModal(); InteractionManager.runAfterInteractions(() => { From 7d284d468cf8cdccdc439abb419ffa0ec5c85143 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 11 Mar 2025 11:15:21 +0100 Subject: [PATCH 3/9] Adjust NavigateToReportWithPolicyCheckPayload type to pass report or reportID --- src/libs/Navigation/Navigation.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 7b956bc73dcbc..7a284f2740ddb 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -5,7 +5,7 @@ import {CommonActions, getPathFromState, StackActions} from '@react-navigation/n import omit from 'lodash/omit'; import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; -import type {Writable} from 'type-fest'; +import type {MergeExclusive, Writable} from 'type-fest'; import getIsNarrowLayout from '@libs/getIsNarrowLayout'; import Log from '@libs/Log'; import {shallowCompare} from '@libs/ObjectUtils'; @@ -470,7 +470,12 @@ function waitForProtectedRoutes() { }); } -type NavigateToReportWithPolicyCheckPayload = {report?: OnyxEntry; reportID?: string; reportActionID?: string; referrer?: string; policyIDToCheck?: string; forceReplace?: boolean}; +// It should not be possible to pass a report and a reportID at the same time. +type NavigateToReportWithPolicyCheckPayload = MergeExclusive<{report?: OnyxEntry}, {reportID?: string}> & { + reportActionID?: string; + referrer?: string; + policyIDToCheck?: string; +}; /** * Navigates to a report passed as a param (as an id or report object) and checks whether the target object belongs to the currently selected workspace. From 1a3a518198f537eaf68915f8e39cec063db7654f Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Tue, 11 Mar 2025 13:52:59 +0100 Subject: [PATCH 4/9] Make report and reportID params of dismissModal function mandatory --- src/libs/Navigation/Navigation.ts | 2 +- src/libs/actions/IOU.ts | 10 +++++----- src/pages/NewChatPage.tsx | 4 ++++ src/pages/TransactionDuplicate/Confirmation.tsx | 6 +++++- src/pages/TransactionReceiptPage.tsx | 7 ++++++- src/pages/workspace/WorkspaceNewRoomPage.tsx | 4 ++++ 6 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts index 7a284f2740ddb..f4e636ae951f1 100644 --- a/src/libs/Navigation/Navigation.ts +++ b/src/libs/Navigation/Navigation.ts @@ -471,7 +471,7 @@ function waitForProtectedRoutes() { } // It should not be possible to pass a report and a reportID at the same time. -type NavigateToReportWithPolicyCheckPayload = MergeExclusive<{report?: OnyxEntry}, {reportID?: string}> & { +type NavigateToReportWithPolicyCheckPayload = MergeExclusive<{report: OnyxEntry}, {reportID: string}> & { reportActionID?: string; referrer?: string; policyIDToCheck?: string; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 808977883005d..5855fe8189d84 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -4758,7 +4758,7 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation) { } InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - if (isSearchTopmostFullScreenRoute()) { + if (isSearchTopmostFullScreenRoute() || !activeReportID) { Navigation.dismissModal(); } else { Navigation.dismissModalWithReport({reportID: activeReportID}); @@ -4846,7 +4846,7 @@ function submitPerDiemExpense(submitPerDiemExpenseInformation: PerDiemExpenseInf API.write(WRITE_COMMANDS.CREATE_PER_DIEM_REQUEST, parameters, onyxData); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - if (isSearchTopmostFullScreenRoute()) { + if (isSearchTopmostFullScreenRoute() || !activeReportID) { Navigation.dismissModal(); } else { Navigation.dismissModalWithReport({reportID: activeReportID}); @@ -5144,7 +5144,7 @@ function trackExpense(params: CreateTrackExpenseParams) { } } InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - if (isSearchTopmostFullScreenRoute()) { + if (isSearchTopmostFullScreenRoute() || !activeReportID) { Navigation.dismissModal(); } else { Navigation.dismissModalWithReport({reportID: activeReportID}); @@ -5731,7 +5731,7 @@ function splitBill({ API.write(WRITE_COMMANDS.SPLIT_BILL, parameters, onyxData); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - if (isSearchTopmostFullScreenRoute()) { + if (isSearchTopmostFullScreenRoute() || !existingSplitChatReportID) { Navigation.dismissModal(); } else { Navigation.dismissModalWithReport({reportID: existingSplitChatReportID}); @@ -6581,7 +6581,7 @@ function createDistanceRequest(distanceRequestInformation: CreateDistanceRequest API.write(WRITE_COMMANDS.CREATE_DISTANCE_REQUEST, parameters, onyxData); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); const activeReportID = isMoneyRequestReport && report?.reportID ? report.reportID : parameters.chatReportID; - if (isSearchTopmostFullScreenRoute()) { + if (isSearchTopmostFullScreenRoute() || !activeReportID) { Navigation.dismissModal(); } else { Navigation.dismissModalWithReport({reportID: activeReportID}); diff --git a/src/pages/NewChatPage.tsx b/src/pages/NewChatPage.tsx index d1bc834c108d7..d3a88c13494a7 100755 --- a/src/pages/NewChatPage.tsx +++ b/src/pages/NewChatPage.tsx @@ -229,6 +229,10 @@ function NewChatPage() { const selectOption = useCallback( (option?: Option) => { if (option?.isSelfDM) { + if (!option.reportID) { + Navigation.dismissModal(); + return; + } Navigation.dismissModalWithReport({reportID: option.reportID}); return; } diff --git a/src/pages/TransactionDuplicate/Confirmation.tsx b/src/pages/TransactionDuplicate/Confirmation.tsx index 0e9f7a86077d4..e6d19a4d98157 100644 --- a/src/pages/TransactionDuplicate/Confirmation.tsx +++ b/src/pages/TransactionDuplicate/Confirmation.tsx @@ -66,7 +66,11 @@ function Confirmation() { const resolveDuplicates = useCallback(() => { IOU.resolveDuplicates(transactionsMergeParams); - Navigation.dismissModalWithReport({reportID: reportAction?.childReportID}); + if (!reportAction?.childReportID) { + Navigation.dismissModal(); + return; + } + Navigation.dismissModalWithReport({reportID: reportAction.childReportID}); }, [transactionsMergeParams, reportAction?.childReportID]); const contextValue = useMemo( diff --git a/src/pages/TransactionReceiptPage.tsx b/src/pages/TransactionReceiptPage.tsx index abda0014c792d..78a35fcd163bf 100644 --- a/src/pages/TransactionReceiptPage.tsx +++ b/src/pages/TransactionReceiptPage.tsx @@ -59,7 +59,12 @@ function TransactionReceipt({route}: TransactionReceiptProps) { Navigation.dismissModal(); } else { const isOneTransactionThread = isOneTransactionThreadReportUtils(report?.reportID, report?.parentReportID, parentReportAction); - Navigation.dismissModalWithReport({reportID: isOneTransactionThread ? report?.parentReportID : report?.reportID}); + const reportID = isOneTransactionThread ? report?.parentReportID : report?.reportID; + if (!reportID) { + Navigation.dismissModal(); + return; + } + Navigation.dismissModalWithReport({reportID}); } }; diff --git a/src/pages/workspace/WorkspaceNewRoomPage.tsx b/src/pages/workspace/WorkspaceNewRoomPage.tsx index 1d665d59af535..4b6b568b389ce 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.tsx +++ b/src/pages/workspace/WorkspaceNewRoomPage.tsx @@ -132,6 +132,10 @@ function WorkspaceNewRoomPage() { if (!(((wasLoading && !isLoading) || (isOffline && isLoading)) && isEmptyObject(errorFields))) { return; } + if (!newRoomReportID) { + Navigation.dismissModal(); + return; + } Navigation.dismissModalWithReport({reportID: newRoomReportID}); // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps -- we just want this to update on changing the form State }, [isLoading, errorFields]); From c643929946e336790615f4ee122bb33cde587dfe Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 12 Mar 2025 08:57:04 +0100 Subject: [PATCH 5/9] Fix imports and default id values --- .../AddBankAccount/AddBankAccount.tsx | 14 +++---- src/pages/tasks/TaskAssigneeSelectorModal.tsx | 40 +++++++++---------- .../workspace/WorkspaceOverviewSharePage.tsx | 16 ++++---- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx index 7bb194b07b481..5b38a557ad2c1 100644 --- a/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx +++ b/src/pages/EnablePayments/AddBankAccount/AddBankAccount.tsx @@ -8,10 +8,10 @@ import useLocalize from '@hooks/useLocalize'; import useSubStep from '@hooks/useSubStep'; import type {SubStepProps} from '@hooks/useSubStep/types'; import useThemeStyles from '@hooks/useThemeStyles'; +import {addPersonalBankAccount, clearPersonalBankAccount} from '@libs/actions/BankAccounts'; +import {continueSetup} from '@libs/actions/PaymentMethods'; +import {updateCurrentStep} from '@libs/actions/Wallet'; import Navigation from '@navigation/Navigation'; -import * as BankAccounts from '@userActions/BankAccounts'; -import * as PaymentMethods from '@userActions/PaymentMethods'; -import * as Wallet from '@userActions/Wallet'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -32,7 +32,7 @@ function AddBankAccount() { const selectedPlaidBankAccount = bankAccounts.find((bankAccount) => bankAccount.plaidAccountID === personalBankAccountDraft?.plaidAccountID); if (selectedPlaidBankAccount) { - BankAccounts.addPersonalBankAccount(selectedPlaidBankAccount); + addPersonalBankAccount(selectedPlaidBankAccount); } }, [personalBankAccountDraft?.plaidAccountID, plaidData?.bankAccounts]); @@ -49,7 +49,7 @@ function AddBankAccount() { return; } if (shouldContinue && onSuccessFallbackRoute) { - PaymentMethods.continueSetup(onSuccessFallbackRoute); + continueSetup(onSuccessFallbackRoute); return; } Navigation.goBack(ROUTES.SETTINGS_WALLET); @@ -61,8 +61,8 @@ function AddBankAccount() { return; } if (screenIndex === 0) { - BankAccounts.clearPersonalBankAccount(); - Wallet.updateCurrentStep(null); + clearPersonalBankAccount(); + updateCurrentStep(null); Navigation.goBack(ROUTES.SETTINGS_WALLET); return; } diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.tsx b/src/pages/tasks/TaskAssigneeSelectorModal.tsx index fbfefaefec8c3..7611f448dd7ca 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.tsx +++ b/src/pages/tasks/TaskAssigneeSelectorModal.tsx @@ -18,15 +18,15 @@ import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails' import useDebouncedState from '@hooks/useDebouncedState'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import * as ReportActions from '@libs/actions/Report'; +import {searchInServer} from '@libs/actions/Report'; +import {canModifyTask, editTaskAssignee, setAssigneeValue} from '@libs/actions/Task'; import {READ_COMMANDS} from '@libs/API/types'; import HttpUtils from '@libs/HttpUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; -import * as ReportUtils from '@libs/ReportUtils'; +import {filterAndOrderOptions, getHeaderMessage, getValidOptions, isCurrentUser} from '@libs/OptionsListUtils'; +import {isOpenTaskReport, isTaskReport} from '@libs/ReportUtils'; import type {TaskDetailsNavigatorParamList} from '@navigation/types'; -import * as TaskActions from '@userActions/Task'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -40,7 +40,7 @@ function useOptions() { const {options: optionsList, areOptionsInitialized} = useOptionsList(); const defaultOptions = useMemo(() => { - const {recentReports, personalDetails, userToInvite, currentUserOption} = OptionsListUtils.getValidOptions( + const {recentReports, personalDetails, userToInvite, currentUserOption} = getValidOptions( { reports: optionsList.reports, personalDetails: optionsList.personalDetails, @@ -51,7 +51,7 @@ function useOptions() { }, ); - const headerMessage = OptionsListUtils.getHeaderMessage((recentReports?.length || 0) + (personalDetails?.length || 0) !== 0 || !!currentUserOption, !!userToInvite, ''); + const headerMessage = getHeaderMessage((recentReports?.length || 0) + (personalDetails?.length || 0) !== 0 || !!currentUserOption, !!userToInvite, ''); if (isLoading) { // eslint-disable-next-line react-compiler/react-compiler @@ -68,11 +68,11 @@ function useOptions() { }, [optionsList.reports, optionsList.personalDetails, betas, isLoading]); const options = useMemo(() => { - const filteredOptions = OptionsListUtils.filterAndOrderOptions(defaultOptions, debouncedSearchValue.trim(), { + const filteredOptions = filterAndOrderOptions(defaultOptions, debouncedSearchValue.trim(), { excludeLogins: CONST.EXPENSIFY_EMAILS_OBJECT, maxRecentReportsToShow: CONST.IOU.MAX_RECENT_REPORTS_TO_SHOW, }); - const headerMessage = OptionsListUtils.getHeaderMessage( + const headerMessage = getHeaderMessage( (filteredOptions.recentReports?.length || 0) + (filteredOptions.personalDetails?.length || 0) !== 0 || !!filteredOptions.currentUserOption, !!filteredOptions.userToInvite, debouncedSearchValue, @@ -104,7 +104,7 @@ function TaskAssigneeSelectorModal() { return; } const reportOnyx = reports?.[`${ONYXKEYS.COLLECTION.REPORT}${route.params?.reportID}`]; - if (reportOnyx && !ReportUtils.isTaskReport(reportOnyx)) { + if (reportOnyx && !isTaskReport(reportOnyx)) { Navigation.isNavigationReady().then(() => { Navigation.dismissModalWithReport({reportID: reportOnyx.reportID}); }); @@ -167,27 +167,27 @@ function TaskAssigneeSelectorModal() { // Check to see if we're editing a task and if so, update the assignee if (report) { if (option.accountID !== report.managerID) { - const assigneeChatReport = TaskActions.setAssigneeValue( + const assigneeChatReport = setAssigneeValue( option?.login ?? '', - option?.accountID ?? -1, + option?.accountID ?? CONST.DEFAULT_NUMBER_ID, report.reportID, undefined, // passing null as report because for editing task the report will be task details report page not the actual report where task was created - OptionsListUtils.isCurrentUser({...option, accountID: option?.accountID ?? -1, login: option?.login ?? ''}), + isCurrentUser({...option, accountID: option?.accountID ?? CONST.DEFAULT_NUMBER_ID, login: option?.login ?? ''}), ); // Pass through the selected assignee - TaskActions.editTaskAssignee(report, session?.accountID ?? -1, option?.login ?? '', option?.accountID, assigneeChatReport); + editTaskAssignee(report, session?.accountID ?? CONST.DEFAULT_NUMBER_ID, option?.login ?? '', option?.accountID, assigneeChatReport); } InteractionManager.runAfterInteractions(() => { Navigation.dismissModalWithReport({reportID: report?.reportID}); }); // If there's no report, we're creating a new task } else if (option.accountID) { - TaskActions.setAssigneeValue( + setAssigneeValue( option?.login ?? '', - option.accountID ?? -1, + option.accountID ?? CONST.DEFAULT_NUMBER_ID, task?.shareDestination ?? '', undefined, // passing null as report is null in this condition - OptionsListUtils.isCurrentUser({...option, accountID: option?.accountID ?? -1, login: option?.login ?? undefined}), + isCurrentUser({...option, accountID: option?.accountID ?? CONST.DEFAULT_NUMBER_ID, login: option?.login ?? undefined}), ); InteractionManager.runAfterInteractions(() => { Navigation.goBack(ROUTES.NEW_TASK.getRoute(backTo)); @@ -199,12 +199,12 @@ function TaskAssigneeSelectorModal() { const handleBackButtonPress = useCallback(() => Navigation.goBack(!route.params?.reportID ? ROUTES.NEW_TASK.getRoute(backTo) : backTo), [route.params, backTo]); - const isOpen = ReportUtils.isOpenTaskReport(report); - const canModifyTask = TaskActions.canModifyTask(report, currentUserPersonalDetails.accountID); - const isTaskNonEditable = ReportUtils.isTaskReport(report) && (!canModifyTask || !isOpen); + const isOpen = isOpenTaskReport(report); + const canModifyTaskValue = canModifyTask(report, currentUserPersonalDetails.accountID); + const isTaskNonEditable = isTaskReport(report) && (!canModifyTaskValue || !isOpen); useEffect(() => { - ReportActions.searchInServer(debouncedSearchValue); + searchInServer(debouncedSearchValue); }, [debouncedSearchValue]); return ( diff --git a/src/pages/workspace/WorkspaceOverviewSharePage.tsx b/src/pages/workspace/WorkspaceOverviewSharePage.tsx index a01acab815421..a2a84a496e48b 100644 --- a/src/pages/workspace/WorkspaceOverviewSharePage.tsx +++ b/src/pages/workspace/WorkspaceOverviewSharePage.tsx @@ -20,9 +20,9 @@ import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import Clipboard from '@libs/Clipboard'; import Navigation from '@libs/Navigation/Navigation'; -import * as ReportUtils from '@libs/ReportUtils'; +import {getDefaultWorkspaceAvatar, getRoom} from '@libs/ReportUtils'; import shouldAllowDownloadQRCode from '@libs/shouldAllowDownloadQRCode'; -import * as Url from '@libs/Url'; +import {addTrailingForwardSlash} from '@libs/Url'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import AccessOrNotFoundWrapper from './AccessOrNotFoundWrapper'; @@ -39,17 +39,17 @@ function WorkspaceOverviewSharePage({policy}: WithPolicyProps) { const session = useSession(); const policyName = policy?.name ?? ''; - const policyID = policy?.id ?? '-1'; + const policyID = policy?.id; const adminEmail = session?.email ?? ''; - const urlWithTrailingSlash = Url.addTrailingForwardSlash(environmentURL); + const urlWithTrailingSlash = addTrailingForwardSlash(environmentURL); - const url = `${urlWithTrailingSlash}${ROUTES.WORKSPACE_JOIN_USER.getRoute(policyID, adminEmail)}`; + const url = `${urlWithTrailingSlash}${ROUTES.WORKSPACE_JOIN_USER.getRoute(policyID ?? '', adminEmail)}`; const hasAvatar = !!policy?.avatarURL; const logo = hasAvatar ? (policy?.avatarURL as ImageSourcePropType) : undefined; - const defaultWorkspaceAvatar = ReportUtils.getDefaultWorkspaceAvatar(policyName) || Expensicons.FallbackAvatar; - const defaultWorkspaceAvatarColors = StyleUtils.getDefaultWorkspaceAvatarColor(policyID); + const defaultWorkspaceAvatar = getDefaultWorkspaceAvatar(policyName) || Expensicons.FallbackAvatar; + const defaultWorkspaceAvatarColors = StyleUtils.getDefaultWorkspaceAvatarColor(policyID ?? ''); const svgLogo = !hasAvatar ? defaultWorkspaceAvatar : undefined; const logoBackgroundColor = !hasAvatar ? defaultWorkspaceAvatarColors.backgroundColor?.toString() : undefined; @@ -59,7 +59,7 @@ function WorkspaceOverviewSharePage({policy}: WithPolicyProps) { if (!policy?.id) { return undefined; } - return ReportUtils.getRoom(CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, policy?.id); + return getRoom(CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, policy?.id); }, [policy?.id]); return ( From 78c2ade4c3ba8fb1c3bbbfa54758a295b7269f81 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 12 Mar 2025 09:30:07 +0100 Subject: [PATCH 6/9] Fix default policyID values in WorkspaceOverviewSharePage --- src/pages/workspace/WorkspaceOverviewSharePage.tsx | 4 ++-- src/styles/utils/index.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/workspace/WorkspaceOverviewSharePage.tsx b/src/pages/workspace/WorkspaceOverviewSharePage.tsx index a2a84a496e48b..fe8d87f73e859 100644 --- a/src/pages/workspace/WorkspaceOverviewSharePage.tsx +++ b/src/pages/workspace/WorkspaceOverviewSharePage.tsx @@ -43,13 +43,13 @@ function WorkspaceOverviewSharePage({policy}: WithPolicyProps) { const adminEmail = session?.email ?? ''; const urlWithTrailingSlash = addTrailingForwardSlash(environmentURL); - const url = `${urlWithTrailingSlash}${ROUTES.WORKSPACE_JOIN_USER.getRoute(policyID ?? '', adminEmail)}`; + const url = policyID ? `${urlWithTrailingSlash}${ROUTES.WORKSPACE_JOIN_USER.getRoute(policyID, adminEmail)}` : ''; const hasAvatar = !!policy?.avatarURL; const logo = hasAvatar ? (policy?.avatarURL as ImageSourcePropType) : undefined; const defaultWorkspaceAvatar = getDefaultWorkspaceAvatar(policyName) || Expensicons.FallbackAvatar; - const defaultWorkspaceAvatarColors = StyleUtils.getDefaultWorkspaceAvatarColor(policyID ?? ''); + const defaultWorkspaceAvatarColors = StyleUtils.getDefaultWorkspaceAvatarColor(policyID); const svgLogo = !hasAvatar ? defaultWorkspaceAvatar : undefined; const logoBackgroundColor = !hasAvatar ? defaultWorkspaceAvatarColors.backgroundColor?.toString() : undefined; diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index 723e4630b29ba..7977953dda7e7 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -276,8 +276,8 @@ function getAvatarBorderStyle(size: AvatarSizeName, type: string): ViewStyle { /** * Helper method to return workspace avatar color styles */ -function getDefaultWorkspaceAvatarColor(text: string): ViewStyle { - const colorHash = hashText(text.trim(), workspaceColorOptions.length); +function getDefaultWorkspaceAvatarColor(text?: string): ViewStyle { + const colorHash = hashText((text ?? '').trim(), workspaceColorOptions.length); return workspaceColorOptions.at(colorHash) ?? {backgroundColor: colors.blue200, fill: colors.blue700}; } From d1e930ac160d8f59530fe0bffaa058dab075d288 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Wed, 19 Mar 2025 15:57:12 +0100 Subject: [PATCH 7/9] Add dismissModalAndOpenReportInInboxTab --- src/libs/actions/IOU.ts | 64 ++++++++++++----------------------------- 1 file changed, 19 insertions(+), 45 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 5855fe8189d84..cb7ce2bdd1286 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -679,6 +679,16 @@ Onyx.connect({ callback: (value) => (personalDetailsList = value), }); +// After finishing the action in RHP from the Inbox tab, besides dismissing the modal, we should open the report. +// It is a helper function used only in this file. +function dismissModalAndOpenReportInInboxTab(reportID?: string) { + if (isSearchTopmostFullScreenRoute() || !reportID) { + Navigation.dismissModal(); + return; + } + Navigation.dismissModalWithReport({reportID}); +} + /** * Find the report preview action from given chat report and iou report */ @@ -4758,11 +4768,7 @@ function requestMoney(requestMoneyInformation: RequestMoneyInformation) { } InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - if (isSearchTopmostFullScreenRoute() || !activeReportID) { - Navigation.dismissModal(); - } else { - Navigation.dismissModalWithReport({reportID: activeReportID}); - } + dismissModalAndOpenReportInInboxTab(activeReportID); const trackReport = Navigation.getReportRouteByID(linkedTrackedExpenseReportAction?.childReportID); if (trackReport?.key) { @@ -4846,11 +4852,7 @@ function submitPerDiemExpense(submitPerDiemExpenseInformation: PerDiemExpenseInf API.write(WRITE_COMMANDS.CREATE_PER_DIEM_REQUEST, parameters, onyxData); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - if (isSearchTopmostFullScreenRoute() || !activeReportID) { - Navigation.dismissModal(); - } else { - Navigation.dismissModalWithReport({reportID: activeReportID}); - } + dismissModalAndOpenReportInInboxTab(activeReportID); if (activeReportID) { notifyNewAction(activeReportID, payeeAccountID); @@ -5144,11 +5146,7 @@ function trackExpense(params: CreateTrackExpenseParams) { } } InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - if (isSearchTopmostFullScreenRoute() || !activeReportID) { - Navigation.dismissModal(); - } else { - Navigation.dismissModalWithReport({reportID: activeReportID}); - } + dismissModalAndOpenReportInInboxTab(activeReportID); if (action === CONST.IOU.ACTION.SHARE) { if (isSearchTopmostFullScreenRoute() && activeReportID) { @@ -5731,11 +5729,7 @@ function splitBill({ API.write(WRITE_COMMANDS.SPLIT_BILL, parameters, onyxData); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - if (isSearchTopmostFullScreenRoute() || !existingSplitChatReportID) { - Navigation.dismissModal(); - } else { - Navigation.dismissModalWithReport({reportID: existingSplitChatReportID}); - } + dismissModalAndOpenReportInInboxTab(existingSplitChatReportID); notifyNewAction(splitData.chatReportID, currentUserAccountID); } @@ -5809,11 +5803,7 @@ function splitBillAndOpenReport({ API.write(WRITE_COMMANDS.SPLIT_BILL_AND_OPEN_REPORT, parameters, onyxData); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - if (isSearchTopmostFullScreenRoute()) { - Navigation.dismissModal(); - } else { - Navigation.dismissModalWithReport({reportID: splitData.chatReportID}); - } + dismissModalAndOpenReportInInboxTab(splitData.chatReportID); notifyNewAction(splitData.chatReportID, currentUserAccountID); } @@ -6394,11 +6384,7 @@ function completeSplitBill( API.write(WRITE_COMMANDS.COMPLETE_SPLIT_BILL, parameters, {optimisticData, successData, failureData}); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); - if (isSearchTopmostFullScreenRoute()) { - Navigation.dismissModal(); - } else { - Navigation.dismissModalWithReport({reportID: chatReportID}); - } + dismissModalAndOpenReportInInboxTab(chatReportID); notifyNewAction(chatReportID, sessionAccountID); } @@ -6581,11 +6567,7 @@ function createDistanceRequest(distanceRequestInformation: CreateDistanceRequest API.write(WRITE_COMMANDS.CREATE_DISTANCE_REQUEST, parameters, onyxData); InteractionManager.runAfterInteractions(() => removeDraftTransaction(CONST.IOU.OPTIMISTIC_TRANSACTION_ID)); const activeReportID = isMoneyRequestReport && report?.reportID ? report.reportID : parameters.chatReportID; - if (isSearchTopmostFullScreenRoute() || !activeReportID) { - Navigation.dismissModal(); - } else { - Navigation.dismissModalWithReport({reportID: activeReportID}); - } + dismissModalAndOpenReportInInboxTab(activeReportID); notifyNewAction(activeReportID, userAccountID); } @@ -8286,11 +8268,7 @@ function sendMoneyElsewhere(report: OnyxEntry, amount: number, API.write(WRITE_COMMANDS.SEND_MONEY_ELSEWHERE, params, {optimisticData, successData, failureData}); - if (isSearchTopmostFullScreenRoute()) { - Navigation.dismissModal(); - } else { - Navigation.dismissModalWithReport({reportID: params.chatReportID}); - } + dismissModalAndOpenReportInInboxTab(params.chatReportID); notifyNewAction(params.chatReportID, managerID); } @@ -8303,11 +8281,7 @@ function sendMoneyWithWallet(report: OnyxEntry, amount: number API.write(WRITE_COMMANDS.SEND_MONEY_WITH_WALLET, params, {optimisticData, successData, failureData}); - if (isSearchTopmostFullScreenRoute()) { - Navigation.dismissModal(); - } else { - Navigation.dismissModalWithReport({reportID: params.chatReportID}); - } + dismissModalAndOpenReportInInboxTab(params.chatReportID); notifyNewAction(params.chatReportID, managerID); } From 46098562642ca313ce2e9350da165bfd746eb324 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 20 Mar 2025 10:56:42 +0100 Subject: [PATCH 8/9] Add private annotation to dismissModalAndOpenReportInInboxTab --- src/libs/actions/IOU.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index cb7ce2bdd1286..5321834fefab5 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -679,8 +679,11 @@ Onyx.connect({ callback: (value) => (personalDetailsList = value), }); -// After finishing the action in RHP from the Inbox tab, besides dismissing the modal, we should open the report. -// It is a helper function used only in this file. +/** + * @private + * After finishing the action in RHP from the Inbox tab, besides dismissing the modal, we should open the report. + * It is a helper function used only in this file. + */ function dismissModalAndOpenReportInInboxTab(reportID?: string) { if (isSearchTopmostFullScreenRoute() || !reportID) { Navigation.dismissModal(); From 6a631c8f09dfddb1820d048105a4e436697b82a2 Mon Sep 17 00:00:00 2001 From: Wojciech Boman Date: Thu, 20 Mar 2025 12:06:13 +0100 Subject: [PATCH 9/9] Set text param of getDefaultWorkspaceAvatarColor function to required --- src/pages/workspace/WorkspaceOverviewSharePage.tsx | 2 +- src/styles/utils/index.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/WorkspaceOverviewSharePage.tsx b/src/pages/workspace/WorkspaceOverviewSharePage.tsx index fe8d87f73e859..47ee741928682 100644 --- a/src/pages/workspace/WorkspaceOverviewSharePage.tsx +++ b/src/pages/workspace/WorkspaceOverviewSharePage.tsx @@ -49,7 +49,7 @@ function WorkspaceOverviewSharePage({policy}: WithPolicyProps) { const logo = hasAvatar ? (policy?.avatarURL as ImageSourcePropType) : undefined; const defaultWorkspaceAvatar = getDefaultWorkspaceAvatar(policyName) || Expensicons.FallbackAvatar; - const defaultWorkspaceAvatarColors = StyleUtils.getDefaultWorkspaceAvatarColor(policyID); + const defaultWorkspaceAvatarColors = policyID ? StyleUtils.getDefaultWorkspaceAvatarColor(policyID) : StyleUtils.getDefaultWorkspaceAvatarColor(''); const svgLogo = !hasAvatar ? defaultWorkspaceAvatar : undefined; const logoBackgroundColor = !hasAvatar ? defaultWorkspaceAvatarColors.backgroundColor?.toString() : undefined; diff --git a/src/styles/utils/index.ts b/src/styles/utils/index.ts index 7977953dda7e7..723e4630b29ba 100644 --- a/src/styles/utils/index.ts +++ b/src/styles/utils/index.ts @@ -276,8 +276,8 @@ function getAvatarBorderStyle(size: AvatarSizeName, type: string): ViewStyle { /** * Helper method to return workspace avatar color styles */ -function getDefaultWorkspaceAvatarColor(text?: string): ViewStyle { - const colorHash = hashText((text ?? '').trim(), workspaceColorOptions.length); +function getDefaultWorkspaceAvatarColor(text: string): ViewStyle { + const colorHash = hashText(text.trim(), workspaceColorOptions.length); return workspaceColorOptions.at(colorHash) ?? {backgroundColor: colors.blue200, fill: colors.blue700}; }