Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
562ac60
feat: update error pattern for delete workspace while on annual subsc…
dominictb Jun 11, 2025
55d9c47
implement offline case
dominictb Jun 11, 2025
754de31
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Jun 25, 2025
752569a
implement API.write approach
dominictb Jun 26, 2025
3ac7286
update languages
dominictb Jun 26, 2025
9c7165c
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Jun 30, 2025
1c5ace8
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Jul 3, 2025
84aa544
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Jul 7, 2025
ad1534b
handle delete in offline
dominictb Jul 8, 2025
d3a155c
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Jul 21, 2025
85428bd
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Jul 23, 2025
61b55a4
show delete annual subscription workspace error in overview page
dominictb Jul 23, 2025
4e7d896
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Jul 24, 2025
a2d1fb9
show loader while pending delete api
dominictb Jul 24, 2025
b39bb4e
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Jul 24, 2025
eee21f0
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Jul 29, 2025
99f8ec5
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Aug 7, 2025
7f81bb0
do not always go back to workspaces list page
dominictb Aug 7, 2025
dd0460a
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Aug 18, 2025
e58a0c3
show all BE workspace error in modal
dominictb Aug 18, 2025
9dabcd8
remove delete_workspace_modal Onyx key and use local modal
dominictb Aug 18, 2025
ea112bd
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Aug 18, 2025
8fff507
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Aug 19, 2025
526acd8
remove redundant copy
dominictb Aug 19, 2025
2934753
Merge Mobile-Expensify
dominictb Aug 19, 2025
2f80944
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Sep 9, 2025
9c80e91
fix lint
dominictb Sep 9, 2025
5a1900d
simplify modal logic to apply modal pattern to all delete workspace e…
dominictb Sep 9, 2025
508b84a
Merge Mobile-Expensify
dominictb Sep 9, 2025
056f562
Merge Mobile-Expensify
dominictb Sep 9, 2025
aa1407f
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Sep 9, 2025
a2f0eb8
Merge
dominictb Sep 9, 2025
534b723
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Sep 11, 2025
8c81159
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Sep 11, 2025
f8dc3ca
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Sep 15, 2025
56b0303
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Sep 17, 2025
ff81cea
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Sep 22, 2025
3f857f9
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Sep 30, 2025
0084700
show all workspace errors in modal pattern
dominictb Sep 30, 2025
dc82334
remove redundant changes
dominictb Sep 30, 2025
ad0f933
fix bugs
dominictb Sep 30, 2025
0f76d1e
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Oct 3, 2025
db90a9d
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Oct 9, 2025
5f70575
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Oct 9, 2025
1978ae8
Merge branch 'main' of github.com-dominictb:dominictb/epsf-app into f…
dominictb Oct 13, 2025
92ecf21
feat: show delete workspace errors in modal
dominictb Oct 13, 2025
cd4ffe6
feat: handle offline case
dominictb Oct 13, 2025
66ec4d9
remove redundant changes
dominictb Oct 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/libs/actions/Policy/Policy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@
};

const allPolicies: OnyxCollection<Policy> = {};
Onyx.connect({

Check warning on line 205 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.POLICY,
callback: (val, key) => {
if (!key) {
Expand Down Expand Up @@ -235,7 +235,7 @@
});

let allReports: OnyxCollection<Report>;
Onyx.connect({

Check warning on line 238 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (value) => {
Expand All @@ -244,7 +244,7 @@
});

let allReportActions: OnyxCollection<ReportActions>;
Onyx.connect({

Check warning on line 247 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
waitForCollectionCallback: true,
callback: (actions) => {
Expand All @@ -254,7 +254,7 @@

let sessionEmail = '';
let sessionAccountID = 0;
Onyx.connect({

Check warning on line 257 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.SESSION,
callback: (val) => {
sessionEmail = val?.email ?? '';
Expand All @@ -263,25 +263,25 @@
});

let allPersonalDetails: OnyxEntry<PersonalDetailsList>;
Onyx.connect({

Check warning on line 266 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
callback: (val) => (allPersonalDetails = val),
});

let allRecentlyUsedCurrencies: string[];
Onyx.connect({

Check warning on line 272 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.RECENTLY_USED_CURRENCIES,
callback: (val) => (allRecentlyUsedCurrencies = val ?? []),
});

let activePolicyID: OnyxEntry<string>;
Onyx.connect({

Check warning on line 278 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.NVP_ACTIVE_POLICY_ID,
callback: (value) => (activePolicyID = value),
});

let introSelected: OnyxEntry<IntroSelected>;
Onyx.connect({

Check warning on line 284 in src/libs/actions/Policy/Policy.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.NVP_INTRO_SELECTED,
callback: (value) => (introSelected = value),
});
Expand Down Expand Up @@ -1815,7 +1815,11 @@
/**
* Removes an error after trying to delete a workspace
*/
function clearDeleteWorkspaceError(policyID: string) {
function clearDeleteWorkspaceError(policyID: string | undefined) {
if (!policyID) {
return;
}

Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {
pendingAction: null,
errors: null,
Expand Down
9 changes: 5 additions & 4 deletions src/pages/workspace/WorkspaceInitialPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {findFocusedRoute, useFocusEffect, useNavigationState} from '@react-navigation/native';
import {findFocusedRoute, useFocusEffect, useIsFocused, useNavigationState} from '@react-navigation/native';
import {emailSelector} from '@selectors/Session';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
Expand Down Expand Up @@ -114,6 +114,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac
const policy = policyDraft?.id ? policyDraft : policyProp;
const workspaceAccountID = policy?.workspaceAccountID ?? CONST.DEFAULT_NUMBER_ID;
const hasPolicyCreationError = policy?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD && !isEmptyObject(policy.errors);
const isFocused = useIsFocused();
const [cardFeeds] = useCardFeeds(policy?.id);
const [allFeedsCards] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}`, {canBeMissing: true});
const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`, {canBeMissing: true});
Expand Down Expand Up @@ -413,19 +414,19 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac

const prevPolicy = usePrevious(policy);

const shouldShowPolicy = useMemo(() => checkIfShouldShowPolicy(policy, false, currentUserLogin), [policy, currentUserLogin]);
const shouldShowPolicy = useMemo(() => checkIfShouldShowPolicy(policy, true, currentUserLogin), [policy, currentUserLogin]);
const isPendingDelete = isPendingDeletePolicy(policy);
const prevIsPendingDelete = isPendingDeletePolicy(prevPolicy);
// We check isPendingDelete and prevIsPendingDelete to prevent the NotFound view from showing right after we delete the workspace
// eslint-disable-next-line rulesdir/no-negated-variables
const shouldShowNotFoundPage = !shouldShowPolicy && (!isPendingDelete || prevIsPendingDelete);

useEffect(() => {
if (isEmptyObject(prevPolicy) || prevIsPendingDelete || !isPendingDelete) {
if (!isFocused || isEmptyObject(prevPolicy) || prevIsPendingDelete || !isPendingDelete) {
return;
}
goBackFromInvalidPolicy();
}, [isPendingDelete, policy, prevIsPendingDelete, prevPolicy]);
}, [isFocused, isPendingDelete, policy, prevIsPendingDelete, prevPolicy]);

// We are checking if the user can access the route.
// If user can't access the route, we are dismissing any modals that are open when the NotFound view is shown
Expand Down
67 changes: 58 additions & 9 deletions src/pages/workspace/WorkspaceOverviewPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useFocusEffect} from '@react-navigation/native';
import {useFocusEffect, useIsFocused} from '@react-navigation/native';
import {accountIDSelector} from '@selectors/Session';
import React, {useCallback, useContext, useEffect, useRef, useState} from 'react';
import type {ImageStyle, StyleProp} from 'react-native';
Expand All @@ -22,6 +22,7 @@ import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
import usePayAndDowngrade from '@hooks/usePayAndDowngrade';
import usePermissions from '@hooks/usePermissions';
import usePrevious from '@hooks/usePrevious';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeIllustrations from '@hooks/useThemeIllustrations';
import useThemeStyles from '@hooks/useThemeStyles';
Expand All @@ -30,6 +31,7 @@ import {clearInviteDraft, clearWorkspaceOwnerChangeFlow, requestWorkspaceOwnerCh
import {
calculateBillNewDot,
clearAvatarErrors,
clearDeleteWorkspaceError,
clearPolicyErrorField,
deleteWorkspace,
deleteWorkspaceAvatar,
Expand All @@ -38,11 +40,11 @@ import {
updateWorkspaceAvatar,
} from '@libs/actions/Policy/Policy';
import {filterInactiveCards} from '@libs/CardUtils';
import {getLatestErrorField} from '@libs/ErrorUtils';
import {getLatestErrorField, getLatestErrorMessage} from '@libs/ErrorUtils';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types';
import {getUserFriendlyWorkspaceType, goBackFromInvalidPolicy, isPolicyAdmin as isPolicyAdminPolicyUtils, isPolicyOwner} from '@libs/PolicyUtils';
import {getUserFriendlyWorkspaceType, goBackFromInvalidPolicy, isPendingDeletePolicy, isPolicyAdmin as isPolicyAdminPolicyUtils, isPolicyOwner} from '@libs/PolicyUtils';
import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils';
import shouldRenderTransferOwnerButton from '@libs/shouldRenderTransferOwnerButton';
import StringUtils from '@libs/StringUtils';
Expand Down Expand Up @@ -160,14 +162,21 @@ function WorkspaceOverviewPage({policyDraft, policy: policyProp, route}: Workspa
const [lastPaymentMethod] = useOnyx(ONYXKEYS.NVP_LAST_PAYMENT_METHOD, {canBeMissing: true});
const {isBetaEnabled} = usePermissions();

const isFocused = useIsFocused();
const isPendingDelete = isPendingDeletePolicy(policy);
const prevIsPendingDelete = usePrevious(isPendingDelete);
const [isDeleteWorkspaceErrorModalOpen, setIsDeleteWorkspaceErrorModalOpen] = useState(false);
const policyLastErrorMessage = getLatestErrorMessage(policy);
const [shouldShowOfflineModal, setShouldShowOfflineModal] = useState(false);

const fetchPolicyData = useCallback(() => {
if (policyDraft?.id) {
return;
}
openPolicyProfilePage(route.params.policyID);
}, [policyDraft?.id, route.params.policyID]);

useNetwork({onReconnect: fetchPolicyData});
const {isOffline} = useNetwork({onReconnect: fetchPolicyData});

// We have the same focus effect in the WorkspaceInitialPage, this way we can get the policy data in narrow
// as well as in the wide layout when looking at policy settings.
Expand Down Expand Up @@ -200,32 +209,52 @@ function WorkspaceOverviewPage({policyDraft, policy: policyProp, route}: Workspa

const dropdownMenuRef = useRef<{setIsMenuVisible: (visible: boolean) => void} | null>(null);

const confirmDeleteAndHideModal = useCallback(() => {
const confirmDelete = useCallback(() => {
if (!policy?.id || !policyName) {
return;
}

deleteWorkspace(policy.id, policyName, lastAccessedWorkspacePolicyID, defaultCardFeeds, reportsToArchive, transactionViolations, reimbursementAccountError, lastPaymentMethod);
setIsDeleteModalOpen(false);
goBackFromInvalidPolicy();
}, [policy?.id, policyName, lastAccessedWorkspacePolicyID, defaultCardFeeds, reportsToArchive, transactionViolations, reimbursementAccountError, lastPaymentMethod]);

const hideDeleteWorkspaceErrorModal = () => {
setIsDeleteWorkspaceErrorModalOpen(false);
clearDeleteWorkspaceError(policy?.id);
};

useEffect(() => {
if (isLoadingBill) {
return;
}
dropdownMenuRef.current?.setIsMenuVisible(false);
}, [isLoadingBill]);

useEffect(() => {
if (!isFocused || !prevIsPendingDelete || isPendingDelete) {
return;
}
setIsDeleteModalOpen(false);
if (!policyLastErrorMessage) {
goBackFromInvalidPolicy();
return;
}
setIsDeleteWorkspaceErrorModalOpen(true);
}, [isFocused, isPendingDelete, prevIsPendingDelete, policyLastErrorMessage]);

const onDeleteWorkspace = useCallback(() => {
if (shouldCalculateBillNewDot()) {
setIsDeletingPaidWorkspace(true);
calculateBillNewDot();
return;
}

if (isOffline) {
setShouldShowOfflineModal(true);
return;
}

setIsDeleteModalOpen(true);
}, [setIsDeletingPaidWorkspace]);
}, [isOffline, setIsDeletingPaidWorkspace]);

const handleBackButtonPress = () => {
if (isComingFromGlobalReimbursementsFlow) {
Expand Down Expand Up @@ -515,13 +544,33 @@ function WorkspaceOverviewPage({policyDraft, policy: policyProp, route}: Workspa
<ConfirmModal
title={translate('workspace.common.delete')}
isVisible={isDeleteModalOpen}
onConfirm={confirmDeleteAndHideModal}
onConfirm={confirmDelete}
onCancel={() => setIsDeleteModalOpen(false)}
prompt={hasCardFeedOrExpensifyCard ? translate('workspace.common.deleteWithCardsConfirmation') : translate('workspace.common.deleteConfirmation')}
confirmText={translate('common.delete')}
cancelText={translate('common.cancel')}
isConfirmLoading={isPendingDeletePolicy(policy)}
danger
/>
<ConfirmModal
title={translate('workspace.common.delete')}
isVisible={isDeleteWorkspaceErrorModalOpen}
onConfirm={hideDeleteWorkspaceErrorModal}
onCancel={hideDeleteWorkspaceErrorModal}
prompt={policyLastErrorMessage}
confirmText={translate('common.buttonConfirm')}
shouldShowCancelButton={false}
success={false}
/>
<ConfirmModal
title={translate('common.youAppearToBeOffline')}
isVisible={shouldShowOfflineModal}
onConfirm={() => setShouldShowOfflineModal(false)}
onCancel={() => setShouldShowOfflineModal(false)}
confirmText={translate('common.buttonConfirm')}
prompt={translate('common.offlinePrompt')}
shouldShowCancelButton={false}
/>
</View>
)}
</WorkspacePageWithSections>
Expand Down
79 changes: 72 additions & 7 deletions src/pages/workspace/WorkspacesListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
import usePayAndDowngrade from '@hooks/usePayAndDowngrade';
import usePreferredPolicy from '@hooks/usePreferredPolicy';
import usePrevious from '@hooks/usePrevious';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useSearchResults from '@hooks/useSearchResults';
import useStyleUtils from '@hooks/useStyleUtils';
Expand All @@ -41,12 +42,21 @@ import {clearWorkspaceOwnerChangeFlow, requestWorkspaceOwnerChange} from '@libs/
import {calculateBillNewDot, clearDeleteWorkspaceError, clearDuplicateWorkspace, clearErrors, deleteWorkspace, leaveWorkspace, removeWorkspace} from '@libs/actions/Policy/Policy';
import {callFunctionIfActionIsAllowed} from '@libs/actions/Session';
import {filterInactiveCards} from '@libs/CardUtils';
import {getLatestErrorMessage} from '@libs/ErrorUtils';
import interceptAnonymousUser from '@libs/interceptAnonymousUser';
import usePreloadFullScreenNavigators from '@libs/Navigation/AppNavigator/usePreloadFullScreenNavigators';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {AuthScreensParamList} from '@libs/Navigation/types';
import {getDefaultApprover, getPolicy, getPolicyBrickRoadIndicatorStatus, getUberConnectionErrorDirectlyFromPolicy, isPolicyAdmin, shouldShowPolicy} from '@libs/PolicyUtils';
import {
getDefaultApprover,
getPolicy,
getPolicyBrickRoadIndicatorStatus,
getUberConnectionErrorDirectlyFromPolicy,
isPendingDeletePolicy,
isPolicyAdmin,
shouldShowPolicy,
} from '@libs/PolicyUtils';
import {getDefaultWorkspaceAvatar} from '@libs/ReportUtils';
import shouldRenderTransferOwnerButton from '@libs/shouldRenderTransferOwnerButton';
import {shouldCalculateBillNewDot as shouldCalculateBillNewDotFn} from '@libs/SubscriptionUtils';
Expand Down Expand Up @@ -125,9 +135,12 @@ function WorkspacesListPage() {

const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [policyIDToDelete, setPolicyIDToDelete] = useState<string>();
// The workspace was deleted in this page
const [policyNameToDelete, setPolicyNameToDelete] = useState<string>();
const {reportsToArchive, transactionViolations} = useTransactionViolationOfWorkspace(policyIDToDelete);
const {setIsDeletingPaidWorkspace, isLoadingBill}: {setIsDeletingPaidWorkspace: (value: boolean) => void; isLoadingBill: boolean | undefined} = usePayAndDowngrade(setIsDeleteModalOpen);
const [isDeleteWorkspaceErrorModalOpen, setIsDeleteWorkspaceErrorModalOpen] = useState(false);
const [shouldShowOfflineModal, setShouldShowOfflineModal] = useState(false);

const [loadingSpinnerIconIndex, setLoadingSpinnerIconIndex] = useState<number | null>(null);

Expand All @@ -148,13 +161,17 @@ function WorkspacesListPage() {
// This will be fixed as part of https://github.com/Expensify/Expensify/issues/507850
// eslint-disable-next-line deprecation/deprecation
const policyToDelete = getPolicy(policyIDToDelete);
const prevPolicyToDelete = usePrevious(policyToDelete);
const hasCardFeedOrExpensifyCard =
!isEmptyObject(cardFeeds) ||
!isEmptyObject(cardsList) ||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
((policyToDelete?.areExpensifyCardsEnabled || policyToDelete?.areCompanyCardsEnabled) && policyToDelete?.workspaceAccountID);
const policyToDeleteLatestErrorMessage = getLatestErrorMessage(policyToDelete);
const isPendingDelete = isPendingDeletePolicy(policyToDelete);
const prevIsPendingDelete = isPendingDeletePolicy(prevPolicyToDelete);

const confirmDeleteAndHideModal = () => {
const confirmDelete = () => {
if (!policyIDToDelete || !policyNameToDelete) {
return;
}
Expand All @@ -169,7 +186,15 @@ function WorkspacesListPage() {
reimbursementAccountError,
lastPaymentMethod,
);
setIsDeleteModalOpen(false);
};

const hideDeleteWorkspaceErrorModal = () => {
setIsDeleteWorkspaceErrorModalOpen(false);
setPolicyIDToDelete(undefined);
if (!policyToDelete) {
return;
}
dismissWorkspaceError(policyToDelete.id, policyToDelete.pendingAction);
};

const shouldCalculateBillNewDot: boolean = shouldCalculateBillNewDotFn();
Expand Down Expand Up @@ -198,6 +223,17 @@ function WorkspacesListPage() {
[session?.accountID],
);

useEffect(() => {
if (!prevIsPendingDelete || isPendingDelete) {
return;
}
setIsDeleteModalOpen(false);
if (!isFocused || !policyToDeleteLatestErrorMessage) {
return;
}
setIsDeleteWorkspaceErrorModalOpen(true);
}, [isPendingDelete, prevIsPendingDelete, isFocused, policyToDeleteLatestErrorMessage]);

/**
* Gets the menu item for each workspace
*/
Expand Down Expand Up @@ -265,6 +301,13 @@ function WorkspacesListPage() {
return;
}

if (isOffline) {
setPolicyIDToDelete(undefined);
setPolicyNameToDelete(undefined);
setShouldShowOfflineModal(true);
return;
}

setIsDeleteModalOpen(true);
},
shouldKeepModalOpen: shouldCalculateBillNewDot,
Expand All @@ -289,6 +332,7 @@ function WorkspacesListPage() {
errors={item.errors}
style={styles.mb2}
shouldShowErrorMessages={false}
shouldHideOnDelete={false}
>
<PressableWithoutFeedback
role={CONST.ROLE.BUTTON}
Expand Down Expand Up @@ -330,9 +374,9 @@ function WorkspacesListPage() {
translate,
policies,
fundList,
styles.ph5,
styles.mb2,
styles.mh5,
styles.ph5,
styles.hoveredComponentBG,
styles.offlineFeedbackDeleted,
loadingSpinnerIconIndex,
Expand All @@ -343,6 +387,7 @@ function WorkspacesListPage() {
isLoadingBill,
resetLoadingSpinnerIconIndex,
isRestrictedToPreferredPolicy,
isOffline,
],
);

Expand All @@ -368,7 +413,7 @@ function WorkspacesListPage() {
}

return Object.values(policies)
.filter((policy): policy is PolicyType => shouldShowPolicy(policy, isOffline, session?.email))
.filter((policy): policy is PolicyType => shouldShowPolicy(policy, true, session?.email))
.map((policy): WorkspaceItem => {
const receiptUberBrickRoadIndicator = getUberConnectionErrorDirectlyFromPolicy(policy as OnyxEntry<PolicyType>) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined;

Expand Down Expand Up @@ -418,7 +463,7 @@ function WorkspacesListPage() {
employeeList: policy.employeeList,
};
});
}, [reimbursementAccount?.errors, policies, isOffline, session?.email, allConnectionSyncProgresses, theme.textLight, navigateToWorkspace]);
}, [reimbursementAccount?.errors, policies, session?.email, allConnectionSyncProgresses, theme.textLight, navigateToWorkspace]);

const filterWorkspace = useCallback((workspace: WorkspaceItem, inputValue: string) => workspace.title.toLowerCase().includes(inputValue), []);
const sortWorkspace = useCallback((workspaceItems: WorkspaceItem[]) => workspaceItems.sort((a, b) => localeCompare(a.title, b.title)), [localeCompare]);
Expand Down Expand Up @@ -570,13 +615,33 @@ function WorkspacesListPage() {
<ConfirmModal
title={translate('workspace.common.delete')}
isVisible={isDeleteModalOpen}
onConfirm={confirmDeleteAndHideModal}
onConfirm={confirmDelete}
onCancel={() => setIsDeleteModalOpen(false)}
prompt={hasCardFeedOrExpensifyCard ? translate('workspace.common.deleteWithCardsConfirmation') : translate('workspace.common.deleteConfirmation')}
confirmText={translate('common.delete')}
cancelText={translate('common.cancel')}
isConfirmLoading={isPendingDelete}
danger
/>
<ConfirmModal
title={translate('workspace.common.delete')}
isVisible={isDeleteWorkspaceErrorModalOpen}
onConfirm={hideDeleteWorkspaceErrorModal}
onCancel={hideDeleteWorkspaceErrorModal}
prompt={policyToDeleteLatestErrorMessage}
confirmText={translate('common.buttonConfirm')}
shouldShowCancelButton={false}
success={false}
/>
<ConfirmModal
title={translate('common.youAppearToBeOffline')}
isVisible={shouldShowOfflineModal}
onConfirm={() => setShouldShowOfflineModal(false)}
onCancel={() => setShouldShowOfflineModal(false)}
confirmText={translate('common.buttonConfirm')}
prompt={translate('common.offlinePrompt')}
shouldShowCancelButton={false}
/>
{shouldDisplayLHB && <NavigationTabBar selectedTab={NAVIGATION_TABS.WORKSPACES} />}
</ScreenWrapper>
);
Expand Down
Loading