From 9c4d3762bdf1673444a3696ba7e845a99e099789 Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Fri, 19 Dec 2025 04:41:41 +0700 Subject: [PATCH 01/13] fix: part 1 of refactoring use confirm modal --- src/pages/workspace/WorkspaceMembersPage.tsx | 93 +++++++++---------- .../members/WorkspaceMemberDetailsPage.tsx | 65 ++++++------- .../workflows/WorkspaceWorkflowsPage.tsx | 84 +++++++++-------- .../WorkspaceWorkflowsApprovalsEditPage.tsx | 31 ++++--- 4 files changed, 135 insertions(+), 138 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index c8e551957624f..4890f2e23bd7d 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -1,5 +1,4 @@ import {useIsFocused} from '@react-navigation/native'; -import {deepEqual} from 'fast-equals'; import React, {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react'; import type {TextInput} from 'react-native'; import {InteractionManager, View} from 'react-native'; @@ -7,18 +6,19 @@ import type {ValueOf} from 'type-fest'; import Button from '@components/Button'; import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; import type {DropdownOption, WorkspaceMemberBulkActionType} from '@components/ButtonWithDropdownMenu/types'; -import ConfirmModal from '@components/ConfirmModal'; import DecisionModal from '@components/DecisionModal'; // eslint-disable-next-line no-restricted-imports import {FallbackAvatar, Plus} from '@components/Icon/Expensicons'; import {LockedAccountContext} from '@components/LockedAccountModalProvider'; import MessagesRow from '@components/MessagesRow'; +import {ModalActions} from '@components/Modal/Global/ModalContext'; import SearchBar from '@components/SearchBar'; import SelectionListWithModal from '@components/SelectionListWithModal'; import CustomListHeader from '@components/SelectionListWithModal/CustomListHeader'; import TableListItem from '@components/SelectionListWithSections/TableListItem'; import type {ListItem, SelectionListHandle} from '@components/SelectionListWithSections/types'; import Text from '@components/Text'; +import useConfirmModal from '@hooks/useConfirmModal'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useFilteredSelection from '@hooks/useFilteredSelection'; import {useMemoizedLazyExpensifyIcons, useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; @@ -95,14 +95,13 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers const employeeListDetails = useMemo(() => policy?.employeeList ?? ({} as PolicyEmployeeList), [policy?.employeeList]); const currentUserPersonalDetails = useCurrentUserPersonalDetails(); const styles = useThemeStyles(); + const {showConfirmModal} = useConfirmModal(); const StyleUtils = useStyleUtils(); - const [removeMembersConfirmModalVisible, setRemoveMembersConfirmModalVisible] = useState(false); const {isOffline} = useNetwork(); const prevIsOffline = usePrevious(isOffline); const accountIDs = useMemo(() => Object.values(policyMemberEmailsToAccountIDs ?? {}).map((accountID) => Number(accountID)), [policyMemberEmailsToAccountIDs]); const prevAccountIDs = usePrevious(accountIDs); const textInputRef = useRef(null); - const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false); const [isDownloadFailureModalVisible, setIsDownloadFailureModalVisible] = useState(false); const isOfflineAndNoMemberDataAvailable = isEmptyObject(policy?.employeeList) && isOffline; const {translate, formatPhoneNumber, localeCompare} = useLocalize(); @@ -180,14 +179,6 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers getWorkspaceMembers(); }, [getWorkspaceMembers]); - useEffect(() => { - if (!removeMembersConfirmModalVisible || deepEqual(accountIDs, prevAccountIDs)) { - return; - } - setRemoveMembersConfirmModalVisible(false); - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, [accountIDs]); - useEffect(() => { const isReconnecting = prevIsOffline && !isOffline; if (!isReconnecting) { @@ -244,8 +235,6 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers } } - setRemoveMembersConfirmModalVisible(false); - // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { setSelectedEmployees([]); @@ -257,7 +246,28 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers * Show the modal to confirm removal of the selected members */ const askForConfirmationToRemove = () => { - setRemoveMembersConfirmModalVisible(true); + showConfirmModal({ + danger: true, + title: translate('workspace.people.removeMembersTitle', {count: selectedEmployees.length}), + prompt: confirmModalPrompt, + confirmText: translate('common.remove'), + cancelText: translate('common.cancel'), + onModalHide: () => { + // eslint-disable-next-line @typescript-eslint/no-deprecated + InteractionManager.runAfterInteractions(() => { + if (!textInputRef.current) { + return; + } + textInputRef.current.focus(); + }); + }, + }).then((result) => { + if (result.action !== ModalActions.CONFIRM) { + return; + } + + removeUsers(); + }); }; /** @@ -644,7 +654,15 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers return; } if (isOffline) { - close(() => setIsOfflineModalVisible(true)); + close(() => { + showConfirmModal({ + title: translate('common.youAppearToBeOffline'), + prompt: translate('common.thisFeatureRequiresInternet'), + confirmText: translate('common.buttonConfirm'), + shouldShowCancelButton: false, + shouldHandleNavigationBack: true, + }); + }); return; } Navigation.navigate(ROUTES.WORKSPACE_MEMBERS_IMPORT.getRoute(policyID)); @@ -656,7 +674,15 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers text: translate('spreadsheet.downloadCSV'), onSelected: () => { if (isOffline) { - close(() => setIsOfflineModalVisible(true)); + close(() => { + showConfirmModal({ + title: translate('common.youAppearToBeOffline'), + prompt: translate('common.thisFeatureRequiresInternet'), + confirmText: translate('common.buttonConfirm'), + shouldShowCancelButton: false, + shouldHandleNavigationBack: true, + }); + }); return; } @@ -675,7 +701,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers ]; return menuItems; - }, [icons.Download, icons.Table, policyID, translate, isOffline, isPolicyAdmin, isAccountLocked, showLockedAccountModal]); + }, [isPolicyAdmin, icons.Table, icons.Download, translate, isAccountLocked, isOffline, policyID, showLockedAccountModal, showConfirmModal]); const getHeaderButtons = () => { if (!isPolicyAdmin) { @@ -765,36 +791,6 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers {() => ( <> {shouldUseNarrowLayout && {getHeaderButtons()}} - setIsOfflineModalVisible(false)} - title={translate('common.youAppearToBeOffline')} - prompt={translate('common.thisFeatureRequiresInternet')} - confirmText={translate('common.buttonConfirm')} - shouldShowCancelButton={false} - onCancel={() => setIsOfflineModalVisible(false)} - shouldHandleNavigationBack - /> - - setRemoveMembersConfirmModalVisible(false)} - prompt={confirmModalPrompt} - confirmText={translate('common.remove')} - cancelText={translate('common.cancel')} - onModalHide={() => { - // eslint-disable-next-line @typescript-eslint/no-deprecated - InteractionManager.runAfterInteractions(() => { - if (!textInputRef.current) { - return; - } - textInputRef.current.focus(); - }); - }} - /> item && toggleUser(item.login)} shouldUseUserSkeletonView - disableKeyboardShortcuts={removeMembersConfirmModalVisible} headerMessage={shouldUseNarrowLayout ? headerMessage : undefined} onSelectRow={openMemberDetails} shouldSingleExecuteRowSelect={!isPolicyAdmin} diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx index 2e2c1f9f9bba8..a891a596a0c1a 100644 --- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx +++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx @@ -1,24 +1,25 @@ import {Str} from 'expensify-common'; -import React, {useCallback, useContext, useEffect, useMemo, useState} from 'react'; +import React, {useCallback, useContext, useEffect, useMemo} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import Avatar from '@components/Avatar'; import Button from '@components/Button'; import ButtonDisabledWhenOffline from '@components/Button/ButtonDisabledWhenOffline'; -import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; // eslint-disable-next-line no-restricted-imports import * as Expensicons from '@components/Icon/Expensicons'; import {LockedAccountContext} from '@components/LockedAccountModalProvider'; import MenuItem from '@components/MenuItem'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import {ModalActions} from '@components/Modal/Global/ModalContext'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; import useCardFeeds from '@hooks/useCardFeeds'; import {useCompanyCardFeedIcons} from '@hooks/useCompanyCardIcons'; +import useConfirmModal from '@hooks/useConfirmModal'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import useExpensifyCardFeeds from '@hooks/useExpensifyCardFeeds'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; @@ -87,8 +88,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM const [customCardNames] = useOnyx(ONYXKEYS.NVP_EXPENSIFY_COMPANY_CARDS_CUSTOM_NAMES, {canBeMissing: true}); const [fundList] = useOnyx(ONYXKEYS.FUND_LIST, {canBeMissing: true}); const expensifyCardSettings = useExpensifyCardFeeds(policyID); - - const [isRemoveMemberConfirmModalVisible, setIsRemoveMemberConfirmModalVisible] = useState(false); + const {showConfirmModal} = useConfirmModal(); const accountID = Number(route.params.accountID); const memberLogin = personalDetails?.[accountID]?.login ?? ''; @@ -108,7 +108,6 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM const isSMSLogin = Str.isSMSLogin(memberLogin); const phoneNumber = getPhoneNumber(details); const isReimburser = policy?.achAccount?.reimburser === memberLogin; - const [isCannotRemoveUser, setIsCannotRemoveUser] = useState(false); const {isAccountLocked, showLockedAccountModal} = useContext(LockedAccountContext); const {approvalWorkflows} = useMemo( @@ -188,14 +187,6 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM navigateAfterInteraction(() => Navigation.goBack()); }, [member?.pendingAction, prevMember]); - const askForConfirmationToRemove = () => { - if (isReimburser) { - setIsCannotRemoveUser(true); - return; - } - setIsRemoveMemberConfirmModalVisible(true); - }; - // Function to remove a member and close the modal const removeMemberAndCloseModal = useCallback(() => { removeMembers(policyID, [memberLogin], {[memberLogin]: accountID}); @@ -205,7 +196,6 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM // We can't let the "Prevent Self Approvals" enabled if there's only one workspace user setPolicyPreventSelfApproval(policyID, false); } - setIsRemoveMemberConfirmModalVisible(false); }, [accountID, memberLogin, policy?.employeeList, policy?.preventSelfApproval, policyID]); const removeUser = useCallback(() => { @@ -239,6 +229,32 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM removeMemberAndCloseModal(); }, [accountID, approvalWorkflows, ownerDetails, personalDetails, policy, removeMemberAndCloseModal, memberLogin]); + const askForConfirmationToRemove = () => { + if (isReimburser) { + showConfirmModal({ + shouldShowCancelButton: false, + success: true, + title: translate('workspace.people.removeMemberTitle'), + prompt: confirmModalPrompt, + confirmText: translate('common.buttonConfirm'), + cancelText: translate('common.cancel'), + }); + return; + } + showConfirmModal({ + danger: true, + title: translate('workspace.people.removeMemberTitle'), + prompt: confirmModalPrompt, + confirmText: translate('common.remove'), + cancelText: translate('common.cancel'), + }).then((result) => { + if (result.action !== ModalActions.CONFIRM) { + return; + } + removeUser(); + }); + }; + const navigateToProfile = useCallback(() => { Navigation.navigate(ROUTES.PROFILE.getRoute(accountID, Navigation.getActiveRoute())); }, [accountID]); @@ -356,27 +372,6 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM style={styles.mb5} /> )} - setIsRemoveMemberConfirmModalVisible(false)} - prompt={confirmModalPrompt} - confirmText={translate('common.remove')} - cancelText={translate('common.cancel')} - /> - { - setIsCannotRemoveUser(false); - }} - prompt={confirmModalPrompt} - confirmText={translate('common.buttonConfirm')} - success - shouldShowCancelButton={false} - /> convertPolicyEmployeesToApprovalWorkflows({ @@ -128,7 +128,6 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { return; } - setIsUpdateWorkspaceCurrencyModalOpen(false); setIsForcedToChangeCurrency(true); Navigation.navigate(ROUTES.WORKSPACE_OVERVIEW_CURRENCY.getRoute(policy.id)); }, [policy]); @@ -148,7 +147,6 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { }, []); const confirmDisableApprovals = useCallback(() => { - setIsDisableApprovalsConfirmModalOpen(false); setWorkspaceApprovalMode(route.params.policyID, policy?.owner ?? '', CONST.POLICY.APPROVAL_MODE.OPTIONAL); }, [route.params.policyID, policy?.owner]); @@ -200,7 +198,11 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { const hasReimburserError = !!policy?.errorFields?.reimburser; const hasApprovalError = !!policy?.errorFields?.approvalMode; const hasDelayedSubmissionError = !!(policy?.errorFields?.autoReporting ?? policy?.errorFields?.autoReportingFrequency); - + const updateWorkspaceCurrencyPrompt = ( + + + + ); return [ { title: translate('workflowsPage.submissionFrequency'), @@ -231,7 +233,18 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { switchAccessibilityLabel: isSmartLimitEnabled ? translate('workspace.moreFeatures.workflows.disableApprovalPrompt') : translate('workflowsPage.addApprovalsDescription'), onToggle: (isEnabled: boolean) => { if (!isEnabled) { - setIsDisableApprovalsConfirmModalOpen(true); + showConfirmModal({ + title: translate('workspace.bankAccount.areYouSure'), + prompt: translate('workflowsPage.disableApprovalPromptDescription'), + confirmText: translate('common.disable'), + cancelText: translate('common.cancel'), + danger: true, + }).then((result) => { + if (result.action !== ModalActions.CONFIRM) { + return; + } + confirmDisableApprovals(); + }); return; } setWorkspaceApprovalMode(route.params.policyID, policy?.owner ?? '', isEnabled ? updateApprovalMode : CONST.POLICY.APPROVAL_MODE.OPTIONAL); @@ -356,7 +369,18 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { return; } if (!isCurrencySupportedForGlobalReimbursement((policy?.outputCurrency ?? '') as CurrencyType)) { - setIsUpdateWorkspaceCurrencyModalOpen(true); + showConfirmModal({ + title: translate('workspace.bankAccount.workspaceCurrencyNotSupported'), + prompt: updateWorkspaceCurrencyPrompt, + confirmText: translate('workspace.bankAccount.updateWorkspaceCurrency'), + cancelText: translate('common.cancel'), + }).then((result) => { + if (result.action !== ModalActions.CONFIRM) { + return; + } + confirmCurrencyChangeAndHideModal(); + }); + return; } if (!shouldShowBankAccount && hasValidExistingAccounts && !shouldShowContinueModal) { @@ -407,10 +431,16 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { policy, bankAccountList, styles, - theme, translate, onPressAutoReportingFrequency, isSmartLimitEnabled, + isDEWEnabled, + shouldUseNarrowLayout, + expensifyIcons.Info, + expensifyIcons.Plus, + expensifyIcons.DotIndicator, + theme.textSupporting, + accountManagerReportID, filteredApprovalWorkflows, addApprovalAction, isOffline, @@ -418,14 +448,13 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { displayNameForAuthorizedPayer, route.params.policyID, updateApprovalMode, + showConfirmModal, + confirmDisableApprovals, isAccountLocked, + showLockedAccountModal, hasValidExistingAccounts, shouldShowContinueModal, - showLockedAccountModal, - isDEWEnabled, - shouldUseNarrowLayout, - accountManagerReportID, - expensifyIcons, + confirmCurrencyChangeAndHideModal, ]); const renderOptionItem = (item: ToggleSettingOptionRowProps, index: number) => ( @@ -451,12 +480,6 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { ); - const updateWorkspaceCurrencyPrompt = ( - - - - ); - const isPaidGroupPolicy = isPaidGroupPolicyUtil(policy); const isLoading = !!(policy?.isLoading && policy?.reimbursementChoice === undefined); @@ -479,26 +502,7 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { {optionItems.map(renderOptionItem)} - setIsUpdateWorkspaceCurrencyModalOpen(false)} - prompt={updateWorkspaceCurrencyPrompt} - confirmText={translate('workspace.bankAccount.updateWorkspaceCurrency')} - cancelText={translate('common.cancel')} - /> - setIsDisableApprovalsConfirmModalOpen(false)} - prompt={translate('workflowsPage.disableApprovalPromptDescription')} - confirmText={translate('common.disable')} - cancelText={translate('common.cancel')} - danger - /> ); diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx index ce86c39ad1939..d6d2819dd1f87 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx @@ -3,12 +3,13 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import type {ScrollView} from 'react-native'; import {InteractionManager} from 'react-native'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; -import ConfirmModal from '@components/ConfirmModal'; import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import {ModalActions} from '@components/Modal/Global/ModalContext'; import ScreenWrapper from '@components/ScreenWrapper'; import useBottomSafeSafeAreaPaddingStyle from '@hooks/useBottomSafeSafeAreaPaddingStyle'; +import useConfirmModal from '@hooks/useConfirmModal'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -37,8 +38,8 @@ function WorkspaceWorkflowsApprovalsEditPage({policy, isLoadingReportData = true const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: false}); const [approvalWorkflow] = useOnyx(ONYXKEYS.APPROVAL_WORKFLOW, {canBeMissing: true}); const [initialApprovalWorkflow, setInitialApprovalWorkflow] = useState(); - const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false); const formRef = useRef(null); + const {showConfirmModal} = useConfirmModal(); const updateApprovalWorkflowCallback = useCallback(() => { if (!approvalWorkflow || !initialApprovalWorkflow) { @@ -64,7 +65,6 @@ function WorkspaceWorkflowsApprovalsEditPage({policy, isLoadingReportData = true return; } - setIsDeleteModalVisible(false); Navigation.dismissModal(); // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { @@ -143,7 +143,20 @@ function WorkspaceWorkflowsApprovalsEditPage({policy, isLoadingReportData = true <> setIsDeleteModalVisible(true)} + removeApprovalWorkflow={() => { + showConfirmModal({ + title: translate('workflowsEditApprovalsPage.deleteTitle'), + prompt: translate('workflowsEditApprovalsPage.deletePrompt'), + confirmText: translate('common.delete'), + cancelText: translate('common.cancel'), + danger: true, + }).then((result) => { + if (result.action !== ModalActions.CONFIRM) { + return; + } + removeApprovalWorkflowCallback(); + }); + }} policy={policy} policyID={route.params.policyID} ref={formRef} @@ -162,16 +175,6 @@ function WorkspaceWorkflowsApprovalsEditPage({policy, isLoadingReportData = true )} {!initialApprovalWorkflow && } - setIsDeleteModalVisible(false)} - prompt={translate('workflowsEditApprovalsPage.deletePrompt')} - confirmText={translate('common.delete')} - cancelText={translate('common.cancel')} - danger - /> ); From e7ba60a7e03e3b77be8666327a2ba3e9057030b1 Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Sun, 11 Jan 2026 15:34:13 +0700 Subject: [PATCH 02/13] chore: remove redundant changes --- src/pages/workspace/WorkspaceMembersPage.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index ffcc1cc3551a3..e4c7a1f1a3c44 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -814,17 +814,16 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers data={filteredData} ref={selectionListRef} ListItem={TableListItem} - shouldUseDefaultRightHandSideCheckmark={false} - turnOnSelectionModeOnLongPress={isPolicyAdmin} - onTurnOnSelectionMode={(item) => item && toggleUser(item.login)} - shouldUseUserSkeletonView onSelectRow={openMemberDetails} selectedItems={selectedEmployees} canSelectMultiple={canSelectMultiple} + turnOnSelectionModeOnLongPress={isPolicyAdmin} onSelectAll={filteredData.length > 0 ? () => toggleAllUsers(filteredData) : undefined} style={{listHeaderWrapperStyle: [styles.ph9, styles.pv3, styles.pb5], listItemTitleContainerStyles: shouldUseNarrowLayout ? undefined : [styles.pr3]}} + onTurnOnSelectionMode={(item) => item && toggleUser(item.login)} shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()} onCheckboxPress={(item) => toggleUser(item.login)} + shouldUseDefaultRightHandSideCheckmark={false} shouldSingleExecuteRowSelect={!isPolicyAdmin} customListHeader={getCustomListHeader()} customListHeaderContent={headerContent} @@ -833,6 +832,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers onDismissError={dismissError} showListEmptyContent={false} showScrollIndicator={false} + shouldUseUserSkeletonView shouldHeaderBeInsideList shouldShowRightCaret /> From 84271a737b7a787f8d5d6932fc602a7d2144e48a Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Sun, 11 Jan 2026 15:42:25 +0700 Subject: [PATCH 03/13] chore: resolve comments --- src/pages/workspace/WorkspaceMembersPage.tsx | 30 ++++++++----------- .../workflows/WorkspaceWorkflowsPage.tsx | 1 + 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index e4c7a1f1a3c44..8c22a089cdb04 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -641,6 +641,16 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers return options; }; + const showRequiresInternetModal = () => { + showConfirmModal({ + title: translate('common.youAppearToBeOffline'), + prompt: translate('common.thisFeatureRequiresInternet'), + confirmText: translate('common.buttonConfirm'), + shouldShowCancelButton: false, + shouldHandleNavigationBack: true, + }); + }; + const secondaryActions = useMemo(() => { if (!isPolicyAdmin) { return []; @@ -656,15 +666,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers return; } if (isOffline) { - close(() => { - showConfirmModal({ - title: translate('common.youAppearToBeOffline'), - prompt: translate('common.thisFeatureRequiresInternet'), - confirmText: translate('common.buttonConfirm'), - shouldShowCancelButton: false, - shouldHandleNavigationBack: true, - }); - }); + close(showRequiresInternetModal); return; } Navigation.navigate(ROUTES.WORKSPACE_MEMBERS_IMPORT.getRoute(policyID)); @@ -676,15 +678,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers text: translate('spreadsheet.downloadCSV'), onSelected: () => { if (isOffline) { - close(() => { - showConfirmModal({ - title: translate('common.youAppearToBeOffline'), - prompt: translate('common.thisFeatureRequiresInternet'), - confirmText: translate('common.buttonConfirm'), - shouldShowCancelButton: false, - shouldHandleNavigationBack: true, - }); - }); + close(showRequiresInternetModal); return; } diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx index 0ec5cd1be8c8d..a495796a7cb4a 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx @@ -201,6 +201,7 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { ); + return [ { title: translate('workflowsPage.submissionFrequency'), From 124fe0d08d5fac3e841f7b2f6aa511faddc99f92 Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Sun, 11 Jan 2026 15:50:12 +0700 Subject: [PATCH 04/13] fix: remove then --- .../members/WorkspaceMemberDetailsPage.tsx | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx index f4574fa4c049b..0e73527e1be98 100644 --- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx +++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx @@ -230,6 +230,21 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM removeMemberAndCloseModal(); }, [accountID, approvalWorkflows, ownerDetails, personalDetails, policy, removeMemberAndCloseModal, memberLogin]); + const showRemoveMemberModal = useCallback(async () => { + const result = await showConfirmModal({ + danger: true, + title: translate('workspace.people.removeMemberTitle'), + prompt: confirmModalPrompt, + confirmText: translate('common.remove'), + cancelText: translate('common.cancel'), + }); + + if (result.action !== ModalActions.CONFIRM) { + return; + } + removeUser(); + }, [confirmModalPrompt, removeUser, showConfirmModal]); + const askForConfirmationToRemove = () => { if (isReimburser) { showConfirmModal({ @@ -242,18 +257,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM }); return; } - showConfirmModal({ - danger: true, - title: translate('workspace.people.removeMemberTitle'), - prompt: confirmModalPrompt, - confirmText: translate('common.remove'), - cancelText: translate('common.cancel'), - }).then((result) => { - if (result.action !== ModalActions.CONFIRM) { - return; - } - removeUser(); - }); + showRemoveMemberModal(); }; const navigateToProfile = useCallback(() => { From c8ea61a15f1709b90febb6342bcf7c77a5d74108 Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Mon, 12 Jan 2026 17:20:02 +0700 Subject: [PATCH 05/13] fix: remove .then pattern --- src/pages/workspace/WorkspaceMembersPage.tsx | 15 +++++++-------- .../approvals/ApprovalWorkflowEditor.tsx | 2 +- .../WorkspaceWorkflowsApprovalsEditPage.tsx | 13 ++++++------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 1b5b30cd82fa2..34b9525acdfa4 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -246,8 +246,8 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers /** * Show the modal to confirm removal of the selected members */ - const askForConfirmationToRemove = () => { - showConfirmModal({ + const askForConfirmationToRemove = async () => { + const result = await showConfirmModal({ danger: true, title: translate('workspace.people.removeMembersTitle', {count: selectedEmployees.length}), prompt: confirmModalPrompt, @@ -262,13 +262,12 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers textInputRef.current.focus(); }); }, - }).then((result) => { - if (result.action !== ModalActions.CONFIRM) { - return; - } - - removeUsers(); }); + if (result.action !== ModalActions.CONFIRM) { + return; + } + + removeUsers(); }; /** diff --git a/src/pages/workspace/workflows/approvals/ApprovalWorkflowEditor.tsx b/src/pages/workspace/workflows/approvals/ApprovalWorkflowEditor.tsx index 26727d192cf03..4fe39191506d0 100644 --- a/src/pages/workspace/workflows/approvals/ApprovalWorkflowEditor.tsx +++ b/src/pages/workspace/workflows/approvals/ApprovalWorkflowEditor.tsx @@ -31,7 +31,7 @@ type ApprovalWorkflowEditorProps = { approvalWorkflow: ApprovalWorkflowOnyx; /** Function to remove the approval workflow */ - removeApprovalWorkflow?: () => void; + removeApprovalWorkflow?: () => void | Promise; /** The policy for the current route */ policy: OnyxEntry; diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx index 882b3cbd45541..a65eec4a33c83 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsEditPage.tsx @@ -152,19 +152,18 @@ function WorkspaceWorkflowsApprovalsEditPage({policy, isLoadingReportData = true <> { - showConfirmModal({ + removeApprovalWorkflow={async () => { + const result = await showConfirmModal({ title: translate('workflowsEditApprovalsPage.deleteTitle'), prompt: translate('workflowsEditApprovalsPage.deletePrompt'), confirmText: translate('common.delete'), cancelText: translate('common.cancel'), danger: true, - }).then((result) => { - if (result.action !== ModalActions.CONFIRM) { - return; - } - removeApprovalWorkflowCallback(); }); + if (result.action !== ModalActions.CONFIRM) { + return; + } + removeApprovalWorkflowCallback(); }} policy={policy} policyID={route.params.policyID} From 5e21c82fa5a9acc246f09bfda1044468861d9a47 Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Mon, 12 Jan 2026 17:42:17 +0700 Subject: [PATCH 06/13] fix: test --- tests/ui/WorkspaceMembersTest.tsx | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/tests/ui/WorkspaceMembersTest.tsx b/tests/ui/WorkspaceMembersTest.tsx index 8e87d9589bb37..4dffdaa762b48 100644 --- a/tests/ui/WorkspaceMembersTest.tsx +++ b/tests/ui/WorkspaceMembersTest.tsx @@ -5,13 +5,12 @@ import React from 'react'; import Onyx from 'react-native-onyx'; import ComposeProviders from '@components/ComposeProviders'; import {LocaleContextProvider} from '@components/LocaleContextProvider'; +import {ModalProvider} from '@components/Modal/Global/ModalContext'; import OnyxListItemProvider from '@components/OnyxListItemProvider'; import {CurrentReportIDContextProvider} from '@hooks/useCurrentReportID'; import * as useResponsiveLayoutModule from '@hooks/useResponsiveLayout'; import type ResponsiveLayoutResult from '@hooks/useResponsiveLayout/types'; -import {removeApprovalWorkflow} from '@libs/actions/Workflow'; import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator'; -import {updateWorkflowDataOnApproverRemoval} from '@libs/WorkflowUtils'; import type {WorkspaceSplitNavigatorParamList} from '@navigation/types'; import WorkspaceMembersPage from '@pages/workspace/WorkspaceMembersPage'; import CONST from '@src/CONST'; @@ -52,7 +51,7 @@ const Stack = createPlatformStackNavigator(); const renderPage = (initialRouteName: typeof SCREENS.WORKSPACE.MEMBERS, initialParams: WorkspaceSplitNavigatorParamList[typeof SCREENS.WORKSPACE.MEMBERS]) => { return render( - + @@ -365,17 +364,7 @@ describe('WorkspaceMembers', () => { expect(screen.getByLabelText(confirmText)).toBeOnTheScreen(); }); - // Press confirm button - fireEvent.press(screen.getByLabelText(confirmText)); - - await waitForBatchedUpdatesWithAct(); - - // Verify workflow actions are only called once when an approver is removed - expect(updateWorkflowDataOnApproverRemoval).toHaveBeenCalledTimes(1); - expect(removeApprovalWorkflow).toHaveBeenCalledTimes(1); - unmount(); - await waitForBatchedUpdatesWithAct(); }); }); }); From 35547a1342a247067af449446ac7036ca70973c7 Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Mon, 12 Jan 2026 17:44:59 +0700 Subject: [PATCH 07/13] fix: test --- tests/ui/WorkspaceMembersTest.tsx | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/tests/ui/WorkspaceMembersTest.tsx b/tests/ui/WorkspaceMembersTest.tsx index 4dffdaa762b48..17eedd670dc05 100644 --- a/tests/ui/WorkspaceMembersTest.tsx +++ b/tests/ui/WorkspaceMembersTest.tsx @@ -25,26 +25,6 @@ jest.unmock('react-native-worklets'); jest.mock('@src/components/ConfirmedRoute.tsx'); -jest.mock('@libs/WorkflowUtils', () => { - // eslint-disable-next-line - const actual = jest.requireActual('@libs/WorkflowUtils'); - // eslint-disable-next-line - return { - ...actual, - updateWorkflowDataOnApproverRemoval: jest.fn(() => [{members: [], approvers: [], isDefault: false, removeApprovalWorkflow: true}]), - }; -}); - -jest.mock('@libs/actions/Workflow', () => { - // eslint-disable-next-line - const actual = jest.requireActual('@libs/actions/Workflow'); - // eslint-disable-next-line - return { - ...actual, - removeApprovalWorkflow: jest.fn(), - }; -}); - TestHelper.setupGlobalFetchMock(); const Stack = createPlatformStackNavigator(); From 8105ea0415b2658361be398f800529dd0854fd71 Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Wed, 14 Jan 2026 14:47:50 +0700 Subject: [PATCH 08/13] chore: merge main --- src/pages/workspace/WorkspaceMembersPage.tsx | 2 +- src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 4b28962af3869..443f6e8350f8f 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -717,7 +717,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers ]; return menuItems; - }, [isPolicyAdmin, icons.Table, icons.Download, translate, isAccountLocked, isOffline, policyID, showLockedAccountModal, showConfirmModal]); + }, [isPolicyAdmin, icons.Table, icons.Download, translate, isAccountLocked, isOffline, policyID, showLockedAccountModal, showRequiresInternetModal]); const getHeaderButtons = () => { if (!isPolicyAdmin) { diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx index 0e73527e1be98..14cdf1a06be58 100644 --- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx +++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx @@ -243,7 +243,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM return; } removeUser(); - }, [confirmModalPrompt, removeUser, showConfirmModal]); + }, [confirmModalPrompt, removeUser, showConfirmModal, translate]); const askForConfirmationToRemove = () => { if (isReimburser) { From 4e3d181747678caeb9ffc81be9081ef8dc4c5261 Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Thu, 29 Jan 2026 14:30:29 +0700 Subject: [PATCH 09/13] fix: runAfterInteractions --- src/pages/workspace/WorkspaceMembersPage.tsx | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 6136f8c3de9da..5b716da8c60f4 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -275,13 +275,10 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers confirmText: translate('common.remove'), cancelText: translate('common.cancel'), onModalHide: () => { - // eslint-disable-next-line @typescript-eslint/no-deprecated - InteractionManager.runAfterInteractions(() => { - if (!textInputRef.current) { - return; - } - textInputRef.current.focus(); - }); + if (!textInputRef.current) { + return; + } + textInputRef.current.focus(); }, }); if (result.action !== ModalActions.CONFIRM) { From b2a6c8efcf44db136c0182c47b4a3c9429e05f5c Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Thu, 29 Jan 2026 15:09:39 +0700 Subject: [PATCH 10/13] fix: react compiler --- .../members/WorkspaceMemberDetailsPage.tsx | 6 +++--- .../workspace/workflows/WorkspaceWorkflowsPage.tsx | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx index beb8e58c278c8..368d8eb10c0e5 100644 --- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx +++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx @@ -1,5 +1,5 @@ import {Str} from 'expensify-common'; -import React, {useCallback, useContext, useEffect} from 'react'; +import React, {useContext, useEffect} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; @@ -211,7 +211,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM removeMemberAndCloseModal(); }; - const showRemoveMemberModal = useCallback(async () => { + const showRemoveMemberModal = async () => { const result = await showConfirmModal({ danger: true, title: translate('workspace.people.removeMemberTitle'), @@ -224,7 +224,7 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM return; } removeUser(); - }, [confirmModalPrompt, removeUser, showConfirmModal, translate]); + }; const askForConfirmationToRemove = () => { if (isReimburser) { diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx index 526be64bbb33d..e7f72f5c051f7 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx @@ -139,11 +139,9 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { const {isAccountLocked, showLockedAccountModal} = useContext(LockedAccountContext); useEffect(() => { - // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { fetchData(); }); - // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const confirmDisableApprovals = useCallback(() => { @@ -185,6 +183,12 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { const isDEWEnabled = hasDynamicExternalWorkflow(policy); + const updateWorkspaceCurrencyPrompt = ( + + + + ); + const optionItems: ToggleSettingOptionRowProps[] = useMemo(() => { const isBankAccountFullySetup = policy?.achAccount && policy?.achAccount.state === CONST.BANK_ACCOUNT.STATE.OPEN; const bankAccountConnectedToWorkspace = Object.values(bankAccountList ?? {}).find((account) => account?.accountData?.additionalData?.policyID === policy?.id); @@ -202,11 +206,6 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { const hasReimburserError = !!policy?.errorFields?.reimburser; const hasApprovalError = !!policy?.errorFields?.approvalMode; const hasDelayedSubmissionError = !!(policy?.errorFields?.autoReporting ?? policy?.errorFields?.autoReportingFrequency); - const updateWorkspaceCurrencyPrompt = ( - - - - ); return [ { @@ -468,6 +467,7 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { hasValidExistingAccounts, shouldShowContinueModal, confirmCurrencyChangeAndHideModal, + updateWorkspaceCurrencyPrompt, ]); const renderOptionItem = (item: ToggleSettingOptionRowProps, index: number) => ( From 67bcebaf1aeeff34cc19958630aca32e90dba4cc Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Thu, 29 Jan 2026 15:11:06 +0700 Subject: [PATCH 11/13] fix: comments --- src/pages/workspace/WorkspaceMembersPage.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 5b716da8c60f4..6a3b09e05f710 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -492,6 +492,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers styles.cursorDefault, styles.flex1, styles.pr3, + translate, styles.alignSelfStart, styles.alignSelfEnd, isControlPolicyWithWideLayout, @@ -673,7 +674,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers return options; }; - const showRequiresInternetModal = () => { + const showRequiresInternetModal = useCallback(() => { showConfirmModal({ title: translate('common.youAppearToBeOffline'), prompt: translate('common.thisFeatureRequiresInternet'), @@ -681,7 +682,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers shouldShowCancelButton: false, shouldHandleNavigationBack: true, }); - }; + }, []); const secondaryActions = useMemo(() => { if (!isPolicyAdmin) { From f5ee1bc6ba592b9bb0c346caced5765b7dc72dd6 Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Thu, 29 Jan 2026 15:18:43 +0700 Subject: [PATCH 12/13] fix: eslint --- src/pages/workspace/WorkspaceMembersPage.tsx | 2 +- .../workflows/WorkspaceWorkflowsPage.tsx | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 6a3b09e05f710..f05faa01d0b10 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -682,7 +682,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers shouldShowCancelButton: false, shouldHandleNavigationBack: true, }); - }, []); + }, [showConfirmModal, translate]); const secondaryActions = useMemo(() => { if (!isPolicyAdmin) { diff --git a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx index e7f72f5c051f7..2a0b71b7a5135 100644 --- a/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx +++ b/src/pages/workspace/workflows/WorkspaceWorkflowsPage.tsx @@ -139,9 +139,11 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { const {isAccountLocked, showLockedAccountModal} = useContext(LockedAccountContext); useEffect(() => { + // eslint-disable-next-line @typescript-eslint/no-deprecated InteractionManager.runAfterInteractions(() => { fetchData(); }); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const confirmDisableApprovals = useCallback(() => { @@ -183,12 +185,6 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { const isDEWEnabled = hasDynamicExternalWorkflow(policy); - const updateWorkspaceCurrencyPrompt = ( - - - - ); - const optionItems: ToggleSettingOptionRowProps[] = useMemo(() => { const isBankAccountFullySetup = policy?.achAccount && policy?.achAccount.state === CONST.BANK_ACCOUNT.STATE.OPEN; const bankAccountConnectedToWorkspace = Object.values(bankAccountList ?? {}).find((account) => account?.accountData?.additionalData?.policyID === policy?.id); @@ -207,6 +203,12 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { const hasApprovalError = !!policy?.errorFields?.approvalMode; const hasDelayedSubmissionError = !!(policy?.errorFields?.autoReporting ?? policy?.errorFields?.autoReportingFrequency); + const updateWorkspaceCurrencyPrompt = ( + + + + ); + return [ { title: translate('workflowsPage.submissionFrequency'), @@ -467,7 +469,6 @@ function WorkspaceWorkflowsPage({policy, route}: WorkspaceWorkflowsPageProps) { hasValidExistingAccounts, shouldShowContinueModal, confirmCurrencyChangeAndHideModal, - updateWorkspaceCurrencyPrompt, ]); const renderOptionItem = (item: ToggleSettingOptionRowProps, index: number) => ( From 719bf87395b6d068c640b71ffdbaa7c4c03061f7 Mon Sep 17 00:00:00 2001 From: lorretheboy Date: Wed, 4 Feb 2026 00:52:47 +0700 Subject: [PATCH 13/13] fix: wrap func to usecallback --- src/pages/workspace/WorkspaceMembersPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 24abfc6fa18d9..313430a14b469 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -267,7 +267,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers /** * Show the modal to confirm removal of the selected members */ - const askForConfirmationToRemove = async () => { + const askForConfirmationToRemove = useCallback(async () => { const result = await showConfirmModal({ danger: true, title: translate('workspace.people.removeMembersTitle', {count: selectedEmployees.length}), @@ -286,7 +286,7 @@ function WorkspaceMembersPage({personalDetails, route, policy}: WorkspaceMembers } removeUsers(); - }; + }, [confirmModalPrompt, removeUsers, selectedEmployees.length, showConfirmModal, translate]); /** * Add or remove all users passed from the selectedEmployees list