diff --git a/src/pages/DynamicReportChangeWorkspacePage.tsx b/src/pages/DynamicReportChangeWorkspacePage.tsx index bbf7c62d8ff6..66188bba3304 100644 --- a/src/pages/DynamicReportChangeWorkspacePage.tsx +++ b/src/pages/DynamicReportChangeWorkspacePage.tsx @@ -54,7 +54,7 @@ import type {DismissedProductTraining} from '@src/types/onyx'; import type {OnyxEntry} from 'react-native-onyx'; import {isTrackIntentUserSelector} from '@selectors/Onboarding'; -import React from 'react'; +import React, {useState} from 'react'; import {View} from 'react-native'; import type {WithReportOrNotFoundProps} from './inbox/report/withReportOrNotFound'; @@ -117,6 +117,9 @@ function DynamicReportChangeWorkspacePage({report}: DynamicReportChangeWorkspace const {currentSearchResults} = useSearchResultsContext(); const shouldCalculateTotals = useSearchShouldCalculateTotals(currentSearchKey, currentSearchQueryJSON?.hash, true); + const [draftPolicyID, setDraftPolicyID] = useState(); + const currentSelection = draftPolicyID ?? report.policyID; + // The snapshot keeps the report row after a workspace change, and only the server can tell whether it still matches the query. const refreshSearch = () => { refreshSearchAfterReportAction({ @@ -215,7 +218,7 @@ function DynamicReportChangeWorkspacePage({report}: DynamicReportChangeWorkspace policies, currentUserLogin: session?.email, shouldShowPendingDeletePolicy: false, - selectedPolicyIDs: report.policyID ? [report.policyID] : undefined, + selectedPolicyIDs: currentSelection ? [currentSelection] : undefined, searchTerm: debouncedSearchTerm, localeCompare, additionalFilter: (newPolicy) => { @@ -235,6 +238,13 @@ function DynamicReportChangeWorkspacePage({report}: DynamicReportChangeWorkspace headerMessage: shouldShowNoResultsFoundMessage ? translate('common.noResultsFound') : '', }; + const confirmButtonOptions = { + showButton: true, + text: translate('common.save'), + onConfirm: () => selectPolicy(currentSelection), + isDisabled: !currentSelection || currentSelection === report.policyID, + }; + if (!isMoneyRequestReport(report) || isMoneyRequestReportPendingDeletion(report) || hasCommuterExclusionDistanceRequest) { return ; } @@ -242,7 +252,7 @@ function DynamicReportChangeWorkspacePage({report}: DynamicReportChangeWorkspace return ( {({didScreenTransitionEnd}) => ( @@ -261,11 +271,13 @@ function DynamicReportChangeWorkspacePage({report}: DynamicReportChangeWorkspace ListItem={UserListItem} data={data} - onSelectRow={(option) => selectPolicy(option.policyID)} + onSelectRow={(option) => setDraftPolicyID(option.policyID)} textInputOptions={textInputOptions} + confirmButtonOptions={confirmButtonOptions} initiallyFocusedItemKey={report.policyID} shouldShowLoadingPlaceholder={fetchStatus.status === 'loading' || !didScreenTransitionEnd} disableMaintainingScrollPosition + addBottomSafeAreaPadding /> )} diff --git a/src/pages/SetDefaultWorkspacePage.tsx b/src/pages/SetDefaultWorkspacePage.tsx index 91cfc0b3ca65..97f8e052b338 100644 --- a/src/pages/SetDefaultWorkspacePage.tsx +++ b/src/pages/SetDefaultWorkspacePage.tsx @@ -27,7 +27,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; -import React, {useMemo} from 'react'; +import React, {useMemo, useState} from 'react'; import {View} from 'react-native'; type SetDefaultWorkspacePageProps = PlatformStackScreenProps; @@ -46,6 +46,9 @@ function SetDefaultWorkspacePage({route}: SetDefaultWorkspacePageProps) { const shouldShowLoadingIndicator = isAppLoadPending && !isOffline; const session = useSession(); + const [draftPolicyID, setDraftPolicyID] = useState(); + const currentSelection = draftPolicyID ?? activePolicyID; + const selectPolicy = (selectedPolicyID?: string) => { if (!selectedPolicyID) { return; @@ -72,12 +75,19 @@ function SetDefaultWorkspacePage({route}: SetDefaultWorkspacePageProps) { policies, currentUserLogin: session?.email, shouldShowPendingDeletePolicy: false, - selectedPolicyIDs: undefined, + selectedPolicyIDs: draftPolicyID ? [draftPolicyID] : undefined, searchTerm: debouncedSearchTerm, localeCompare, additionalFilter: (newPolicy) => isGroupPolicy(newPolicy), }); + const confirmButtonOptions = { + showButton: true, + text: translate('common.save'), + onConfirm: () => selectPolicy(currentSelection), + isDisabled: currentSelection === activePolicyID, + }; + const textInputOptions = useMemo( () => ({ label: shouldShowSearchInput ? translate('common.search') : undefined, @@ -91,7 +101,7 @@ function SetDefaultWorkspacePage({route}: SetDefaultWorkspacePageProps) { return ( {({didScreenTransitionEnd}) => ( @@ -109,9 +119,11 @@ function SetDefaultWorkspacePage({route}: SetDefaultWorkspacePageProps) { data={data} ListItem={UserListItem} textInputOptions={textInputOptions} - onSelectRow={(option) => selectPolicy(option.policyID)} + onSelectRow={(option) => setDraftPolicyID(option.policyID)} + confirmButtonOptions={confirmButtonOptions} shouldShowLoadingPlaceholder={fetchStatus.status === 'loading' || !didScreenTransitionEnd} disableMaintainingScrollPosition + addBottomSafeAreaPadding /> )} diff --git a/src/pages/domain/Groups/DomainGroupPreferredWorkspacePage.tsx b/src/pages/domain/Groups/DomainGroupPreferredWorkspacePage.tsx index 33e9d7190905..36297133b230 100644 --- a/src/pages/domain/Groups/DomainGroupPreferredWorkspacePage.tsx +++ b/src/pages/domain/Groups/DomainGroupPreferredWorkspacePage.tsx @@ -23,7 +23,7 @@ import type SCREENS from '@src/SCREENS'; import {domainSecurityGroupSettingPendingActionSelector, selectGroupByID} from '@selectors/Domain'; import {createAdminPoliciesSelector} from '@selectors/Policy'; -import React from 'react'; +import React, {useState} from 'react'; type WorkspaceListItem = { policyID: string; @@ -48,6 +48,9 @@ function DomainGroupPreferredWorkspacePage({route}: DomainGroupPreferredWorkspac const currentPolicyID = group?.restrictedPrimaryPolicyID; + const [selectedPolicyID, setSelectedPolicyID] = useState(); + const currentSelection = selectedPolicyID ?? currentPolicyID; + const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: createAdminPoliciesSelector(currentPolicyID)}); const workspaceOptions: WorkspaceListItem[] = []; @@ -61,10 +64,25 @@ function DomainGroupPreferredWorkspacePage({route}: DomainGroupPreferredWorkspac policyID: policy.id, created: policy.created, keyForList: policy.id, - isSelected: currentPolicyID === policy.id, + isSelected: currentSelection === policy.id, }); } + const saveWorkspace = () => { + if (!group || !currentSelection) { + return; + } + updateDomainSecurityGroup(domainAccountID, groupID, group, {restrictedPrimaryPolicyID: currentSelection}, 'restrictedPrimaryPolicyID'); + Navigation.goBack(ROUTES.DOMAIN_GROUP_DETAILS.getRoute(domainAccountID, groupID)); + }; + + const confirmButtonOptions = { + showButton: true, + text: translate('common.save'), + onConfirm: saveWorkspace, + isDisabled: currentSelection === currentPolicyID, + }; + return ( data={workspaceOptions.sort((a, b) => localeCompare(a.created ?? '', b.created ?? ''))} ListItem={UserListItem} - onSelectRow={(item: WorkspaceListItem) => { - if (!group) { - return; - } - updateDomainSecurityGroup(domainAccountID, groupID, group, {restrictedPrimaryPolicyID: item.policyID}, 'restrictedPrimaryPolicyID'); - Navigation.goBack(ROUTES.DOMAIN_GROUP_DETAILS.getRoute(domainAccountID, groupID)); - }} + onSelectRow={(item: WorkspaceListItem) => setSelectedPolicyID(item.policyID)} + confirmButtonOptions={confirmButtonOptions} initiallyFocusedItemKey={currentPolicyID} shouldUpdateFocusedIndex + addBottomSafeAreaPadding />