diff --git a/src/hooks/useSearchBackPress/index.android.ts b/src/hooks/useSearchBackPress/index.android.ts new file mode 100644 index 000000000000..32aa7bb5b87a --- /dev/null +++ b/src/hooks/useSearchBackPress/index.android.ts @@ -0,0 +1,28 @@ +import {useFocusEffect} from '@react-navigation/native'; +import {useCallback} from 'react'; +import {BackHandler} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; +import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type UseSearchBackPress from './types'; + +const useSearchBackPress: UseSearchBackPress = ({onClearSelection, onNavigationCallBack}) => { + const [selectionMode] = useOnyx(ONYXKEYS.MOBILE_SELECTION_MODE); + useFocusEffect( + useCallback(() => { + const onBackPress = () => { + if (selectionMode?.isEnabled) { + onClearSelection(); + turnOffMobileSelectionMode(); + return true; + } + onNavigationCallBack(); + return false; + }; + const backHandler = BackHandler.addEventListener('hardwareBackPress', onBackPress); + return () => backHandler.remove(); + }, [selectionMode?.isEnabled, onClearSelection, onNavigationCallBack]), + ); +}; + +export default useSearchBackPress; diff --git a/src/hooks/useSearchBackPress/index.ts b/src/hooks/useSearchBackPress/index.ts new file mode 100644 index 000000000000..7cc904a7f31b --- /dev/null +++ b/src/hooks/useSearchBackPress/index.ts @@ -0,0 +1,6 @@ +import type UseSearchBackPress from './types'; + +// the back press event is only supported on Android native +const useSearchBackPress: UseSearchBackPress = () => {}; + +export default useSearchBackPress; diff --git a/src/hooks/useSearchBackPress/types.ts b/src/hooks/useSearchBackPress/types.ts new file mode 100644 index 000000000000..64b1a440b1cf --- /dev/null +++ b/src/hooks/useSearchBackPress/types.ts @@ -0,0 +1,8 @@ +type UseSearchBackPressParams = { + onClearSelection: () => void; + onNavigationCallBack: () => void; +}; + +type UseSearchBackPress = (params: UseSearchBackPressParams) => void; + +export default UseSearchBackPress; diff --git a/src/pages/ReportParticipantsPage.tsx b/src/pages/ReportParticipantsPage.tsx index 32bec2cd751f..bda35fc70b1f 100755 --- a/src/pages/ReportParticipantsPage.tsx +++ b/src/pages/ReportParticipantsPage.tsx @@ -11,7 +11,7 @@ import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; import type {DropdownOption, WorkspaceMemberBulkActionType} from '@components/ButtonWithDropdownMenu/types'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Expensicons from '@components/Icon/Expensicons'; +import {FallbackAvatar, MakeAdmin, Plus, RemoveMembers, User} from '@components/Icon/Expensicons'; import ScreenWrapper from '@components/ScreenWrapper'; import TableListItem from '@components/SelectionList/TableListItem'; import type {ListItem, SelectionListHandle} from '@components/SelectionList/types'; @@ -21,17 +21,30 @@ import useLocalize from '@hooks/useLocalize'; import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useSearchBackPress from '@hooks/useSearchBackPress'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; -import * as Report from '@libs/actions/Report'; -import * as UserSearchPhraseActions from '@libs/actions/RoomMembersUserSearchPhrase'; +import {removeFromGroupChat, updateGroupChatMemberRoles} from '@libs/actions/Report'; +import {clearUserSearchPhrase} from '@libs/actions/RoomMembersUserSearchPhrase'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {ParticipantsNavigatorParamList} from '@libs/Navigation/types'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; -import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; -import * as ReportUtils from '@libs/ReportUtils'; +import {isSearchStringMatchUserDetails} from '@libs/OptionsListUtils'; +import {getDisplayNameOrDefault, getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; +import { + getParticipantsList, + getReportName, + isArchivedNonExpenseReport, + isChatRoom, + isChatThread, + isGroupChatAdmin, + isGroupChat as isGroupChatUtils, + isMoneyRequestReport, + isPolicyExpenseChat, + isSelfDM, + isTaskReport, +} from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -63,8 +76,8 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { const [session] = useOnyx(ONYXKEYS.SESSION); const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST); const currentUserAccountID = Number(session?.accountID); - const isCurrentUserAdmin = ReportUtils.isGroupChatAdmin(report, currentUserAccountID); - const isGroupChat = useMemo(() => ReportUtils.isGroupChat(report), [report]); + const isCurrentUserAdmin = isGroupChatAdmin(report, currentUserAccountID); + const isGroupChat = useMemo(() => isGroupChatUtils(report), [report]); const isFocused = useIsFocused(); const {isOffline} = useNetwork(); const canSelectMultiple = isGroupChat && isCurrentUserAdmin && (isSmallScreenWidth ? selectionMode?.isEnabled : true); @@ -77,7 +90,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { setSelectedMembers([]); }, [isFocused]); - const chatParticipants = ReportUtils.getParticipantsList(report, personalDetails); + const chatParticipants = getParticipantsList(report, personalDetails); const pendingChatMembers = reportMetadata?.pendingChatMembers; const reportParticipants = report?.participants; @@ -102,11 +115,23 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { if (shouldShowTextInput) { setSearchValue(userSearchPhrase ?? ''); } else { - UserSearchPhraseActions.clearUserSearchPhrase(); + clearUserSearchPhrase(); setSearchValue(''); } }, [isFocused, setSearchValue, shouldShowTextInput, userSearchPhrase]); + useSearchBackPress({ + onClearSelection: () => setSelectedMembers([]), + onNavigationCallBack: () => { + if (!report) { + return; + } + + setSearchValue(''); + Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID, backTo)); + }, + }); + const getParticipants = () => { let result: MemberOption[] = []; @@ -115,7 +140,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { const details = personalDetails?.[accountID]; // If search value is provided, filter out members that don't match the search value - if (!details || (searchValue.trim() && !OptionsListUtils.isSearchStringMatchUserDetails(details, searchValue))) { + if (!details || (searchValue.trim() && !isSearchStringMatchUserDetails(details, searchValue))) { return; } @@ -135,13 +160,13 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { isSelected, isDisabledCheckbox: accountID === currentUserAccountID, isDisabled: pendingChatMember?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || details?.isOptimisticPersonalDetail, - text: formatPhoneNumber(PersonalDetailsUtils.getDisplayNameOrDefault(details)), + text: formatPhoneNumber(getDisplayNameOrDefault(details)), alternateText: formatPhoneNumber(details?.login ?? ''), rightElement: roleBadge, pendingAction, icons: [ { - source: details?.avatar ?? Expensicons.FallbackAvatar, + source: details?.avatar ?? FallbackAvatar, name: formatPhoneNumber(details?.login ?? ''), type: CONST.ICON_TYPE_AVATAR, id: accountID, @@ -200,19 +225,19 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { const removeUsers = () => { // Remove the admin from the list const accountIDsToRemove = selectedMembers.filter((id) => id !== currentUserAccountID); - Report.removeFromGroupChat(report.reportID, accountIDsToRemove); + removeFromGroupChat(report.reportID, accountIDsToRemove); setSearchValue(''); setSelectedMembers([]); setRemoveMembersConfirmModalVisible(false); InteractionManager.runAfterInteractions(() => { - UserSearchPhraseActions.clearUserSearchPhrase(); + clearUserSearchPhrase(); }); }; const changeUserRole = useCallback( (role: ValueOf) => { const accountIDsToUpdate = selectedMembers.filter((id) => report.participants?.[id].role !== role); - Report.updateGroupChatMemberRoles(report.reportID, accountIDsToUpdate, role); + updateGroupChatMemberRoles(report.reportID, accountIDsToUpdate, role); setSelectedMembers([]); }, [report, selectedMembers], @@ -263,7 +288,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { { text: translate('workspace.people.removeMembersTitle', {count: selectedMembers.length}), value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.REMOVE, - icon: Expensicons.RemoveMembers, + icon: RemoveMembers, onSelected: () => setRemoveMembersConfirmModalVisible(true), }, ]; @@ -274,7 +299,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { options.push({ text: translate('workspace.people.makeMember'), value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.MAKE_MEMBER, - icon: Expensicons.User, + icon: User, onSelected: () => changeUserRole(CONST.REPORT.ROLE.MEMBER), }); } @@ -285,7 +310,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { options.push({ text: translate('workspace.people.makeAdmin'), value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.MAKE_ADMIN, - icon: Expensicons.MakeAdmin, + icon: MakeAdmin, onSelected: () => changeUserRole(CONST.REPORT.ROLE.ADMIN), }); } @@ -317,7 +342,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { success onPress={inviteUser} text={translate('workspace.invite.member')} - icon={Expensicons.Plus} + icon={Plus} innerStyles={[shouldUseNarrowLayout && styles.alignItemsCenter]} style={[shouldUseNarrowLayout && styles.flexGrow1]} /> @@ -338,14 +363,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { [report, isCurrentUserAdmin, isGroupChat, backTo], ); const headerTitle = useMemo(() => { - if ( - ReportUtils.isChatRoom(report) || - ReportUtils.isPolicyExpenseChat(report) || - ReportUtils.isChatThread(report) || - ReportUtils.isTaskReport(report) || - ReportUtils.isMoneyRequestReport(report) || - isGroupChat - ) { + if (isChatRoom(report) || isPolicyExpenseChat(report) || isChatThread(report) || isTaskReport(report) || isMoneyRequestReport(report) || isGroupChat) { return translate('common.members'); } return translate('common.details'); @@ -365,7 +383,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { style={[styles.defaultModalContainer]} testID={ReportParticipantsPage.displayName} > - + { @@ -381,7 +399,7 @@ function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) { } }} guidesCallTaskID={CONST.GUIDES_CALL_TASK_IDS.WORKSPACE_MEMBERS} - subtitle={StringUtils.lineBreaksToSpaces(ReportUtils.getReportName(report))} + subtitle={StringUtils.lineBreaksToSpaces(getReportName(report))} /> {headerButtons} setRemoveMembersConfirmModalVisible(false)} prompt={translate('workspace.people.removeMembersPrompt', { count: selectedMembers.length, - memberName: formatPhoneNumber(PersonalDetailsUtils.getPersonalDetailsByIDs({accountIDs: selectedMembers, currentUserAccountID}).at(0)?.displayName ?? ''), + memberName: formatPhoneNumber(getPersonalDetailsByIDs({accountIDs: selectedMembers, currentUserAccountID}).at(0)?.displayName ?? ''), })} confirmText={translate('common.remove')} cancelText={translate('common.cancel')} diff --git a/src/pages/RoomMembersPage.tsx b/src/pages/RoomMembersPage.tsx index 447876334b5c..15544388aa09 100644 --- a/src/pages/RoomMembersPage.tsx +++ b/src/pages/RoomMembersPage.tsx @@ -8,7 +8,7 @@ import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; import type {DropdownOption, RoomMemberBulkActionType} from '@components/ButtonWithDropdownMenu/types'; import ConfirmModal from '@components/ConfirmModal'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import * as Expensicons from '@components/Icon/Expensicons'; +import {FallbackAvatar, Plus, RemoveMembers} from '@components/Icon/Expensicons'; import {usePersonalDetails} from '@components/OnyxProvider'; import ScreenWrapper from '@components/ScreenWrapper'; import TableListItem from '@components/SelectionList/TableListItem'; @@ -20,20 +20,21 @@ import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalD import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useSearchBackPress from '@hooks/useSearchBackPress'; import useThemeStyles from '@hooks/useThemeStyles'; import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; -import * as UserSearchPhraseActions from '@libs/actions/RoomMembersUserSearchPhrase'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; +import {clearUserSearchPhrase, updateUserSearchPhrase} from '@libs/actions/RoomMembersUserSearchPhrase'; +import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import localeCompare from '@libs/LocaleCompare'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackRouteProp, PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {RoomMembersNavigatorParamList} from '@libs/Navigation/types'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; -import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import * as ReportUtils from '@libs/ReportUtils'; +import {isPersonalDetailsReady, isSearchStringMatchUserDetails} from '@libs/OptionsListUtils'; +import {getDisplayNameOrDefault, getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; +import {isPolicyEmployee as isPolicyEmployeeUtils, isUserPolicyAdmin} from '@libs/PolicyUtils'; +import {getParticipantsList, getReportName, isChatThread, isDefaultRoom, isPolicyExpenseChat as isPolicyExpenseChatUtils, isUserCreatedPolicyRoom} from '@libs/ReportUtils'; import StringUtils from '@libs/StringUtils'; -import * as Report from '@userActions/Report'; +import {clearAddRoomMemberError, openRoomMembersPage, removeFromRoom} from '@userActions/Report'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -58,7 +59,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { const [didLoadRoomMembers, setDidLoadRoomMembers] = useState(false); const personalDetails = usePersonalDetails(); const policy = useMemo(() => policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`], [policies, report?.policyID]); - const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(report), [report]); + const isPolicyExpenseChat = useMemo(() => isPolicyExpenseChatUtils(report), [report]); const backTo = route.params.backTo; const isFocusedScreen = useIsFocused(); @@ -84,12 +85,12 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { if (!report) { return; } - Report.openRoomMembersPage(report.reportID); + openRoomMembersPage(report.reportID); setDidLoadRoomMembers(true); }, [report]); useEffect(() => { - UserSearchPhraseActions.clearUserSearchPhrase(); + clearUserSearchPhrase(); getRoomMembers(); // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); @@ -111,13 +112,13 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { */ const removeUsers = () => { if (report) { - Report.removeFromRoom(report.reportID, selectedMembers); + removeFromRoom(report.reportID, selectedMembers); } setSearchValue(''); setSelectedMembers([]); setRemoveMembersConfirmModalVisible(false); InteractionManager.runAfterInteractions(() => { - UserSearchPhraseActions.clearUserSearchPhrase(); + clearUserSearchPhrase(); }); }; @@ -170,7 +171,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { } }; - const participants = useMemo(() => ReportUtils.getParticipantsList(report, personalDetails, true), [report, personalDetails]); + const participants = useMemo(() => getParticipantsList(report, personalDetails, true), [report, personalDetails]); /** Include the search bar when there are 8 or more active members in the selection list */ const shouldShowTextInput = useMemo(() => { @@ -194,7 +195,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { }, [isFocusedScreen, shouldShowTextInput, userSearchPhrase]); useEffect(() => { - UserSearchPhraseActions.updateUserSearchPhrase(searchValue); + updateUserSearchPhrase(searchValue); }, [searchValue]); useEffect(() => { @@ -204,11 +205,19 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { if (shouldShowTextInput) { setSearchValue(userSearchPhrase ?? ''); } else { - UserSearchPhraseActions.clearUserSearchPhrase(); + clearUserSearchPhrase(); setSearchValue(''); } }, [isFocusedScreen, setSearchValue, shouldShowTextInput, userSearchPhrase]); + useSearchBackPress({ + onClearSelection: () => setSelectedMembers([]), + onNavigationCallBack: () => { + setSearchValue(''); + Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID, backTo)); + }, + }); + const data = useMemo((): ListItem[] => { let result: ListItem[] = []; @@ -216,11 +225,11 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { const details = personalDetails?.[accountID]; // If search value is provided, filter out members that don't match the search value - if (!details || (searchValue.trim() && !OptionsListUtils.isSearchStringMatchUserDetails(details, searchValue))) { + if (!details || (searchValue.trim() && !isSearchStringMatchUserDetails(details, searchValue))) { return; } const pendingChatMember = reportMetadata?.pendingChatMembers?.findLast((member) => member.accountID === accountID.toString()); - const isAdmin = PolicyUtils.isUserPolicyAdmin(policy, details.login); + const isAdmin = isUserPolicyAdmin(policy, details.login); const isDisabled = pendingChatMember?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || details.isOptimisticPersonalDetail; const isDisabledCheckbox = (isPolicyExpenseChat && isAdmin) || @@ -234,11 +243,11 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { isSelected: selectedMembers.includes(accountID), isDisabled, isDisabledCheckbox, - text: formatPhoneNumber(PersonalDetailsUtils.getDisplayNameOrDefault(details)), + text: formatPhoneNumber(getDisplayNameOrDefault(details)), alternateText: details?.login ? formatPhoneNumber(details.login) : '', icons: [ { - source: details.avatar ?? Expensicons.FallbackAvatar, + source: details.avatar ?? FallbackAvatar, name: details.login ?? '', type: CONST.ICON_TYPE_AVATAR, id: accountID, @@ -267,7 +276,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { const dismissError = useCallback( (item: ListItem) => { - Report.clearAddRoomMemberError(report.reportID, String(item.accountID)); + clearAddRoomMemberError(report.reportID, String(item.accountID)); }, [report.reportID], ); @@ -276,7 +285,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { if (!report?.policyID || policies === null) { return false; } - return PolicyUtils.isPolicyEmployee(report.policyID, policies); + return isPolicyEmployeeUtils(report.policyID, policies); }, [report?.policyID, policies]); const headerMessage = searchValue.trim() && !data.length ? `${translate('roomMembersPage.memberNotFound')} ${translate('roomMembersPage.useInviteButton')}` : ''; @@ -286,7 +295,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { { text: translate('workspace.people.removeMembersTitle', {count: selectedMembers.length}), value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.REMOVE, - icon: Expensicons.RemoveMembers, + icon: RemoveMembers, onSelected: () => setRemoveMembersConfirmModalVisible(true), }, ]; @@ -313,7 +322,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { success onPress={inviteUser} text={translate('workspace.invite.member')} - icon={Expensicons.Plus} + icon={Plus} innerStyles={[shouldUseNarrowLayout && styles.alignItemsCenter]} style={[shouldUseNarrowLayout && styles.flexGrow1]} /> @@ -358,9 +367,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { testID={RoomMembersPage.displayName} > { Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID, backTo)); @@ -368,7 +375,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { > { if (selectionMode?.isEnabled) { setSelectedMembers([]); @@ -389,7 +396,7 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { onCancel={() => setRemoveMembersConfirmModalVisible(false)} prompt={translate('roomMembersPage.removeMembersPrompt', { count: selectedMembers.length, - memberName: formatPhoneNumber(PersonalDetailsUtils.getPersonalDetailsByIDs({accountIDs: selectedMembers, currentUserAccountID}).at(0)?.displayName ?? ''), + memberName: formatPhoneNumber(getPersonalDetailsByIDs({accountIDs: selectedMembers, currentUserAccountID}).at(0)?.displayName ?? ''), })} confirmText={translate('common.remove')} cancelText={translate('common.cancel')} @@ -409,9 +416,9 @@ function RoomMembersPage({report, policies}: RoomMembersPageProps) { onCheckboxPress={(item) => toggleUser(item)} onSelectRow={openRoomMemberDetails} onSelectAll={() => toggleAllUsers(data)} - showLoadingPlaceholder={!OptionsListUtils.isPersonalDetailsReady(personalDetails) || !didLoadRoomMembers} + showLoadingPlaceholder={!isPersonalDetailsReady(personalDetails) || !didLoadRoomMembers} showScrollIndicator - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} + shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()} listHeaderWrapperStyle={[styles.ph9, styles.mt3]} customListHeader={customListHeader} ListItem={TableListItem} diff --git a/src/pages/workspace/WorkspaceMembersPage.tsx b/src/pages/workspace/WorkspaceMembersPage.tsx index 7531b8d71c83..14df1fb1811f 100644 --- a/src/pages/workspace/WorkspaceMembersPage.tsx +++ b/src/pages/workspace/WorkspaceMembersPage.tsx @@ -12,8 +12,8 @@ import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu'; import type {DropdownOption, WorkspaceMemberBulkActionType} from '@components/ButtonWithDropdownMenu/types'; import ConfirmModal from '@components/ConfirmModal'; import DecisionModal from '@components/DecisionModal'; -import * as Expensicons from '@components/Icon/Expensicons'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {Download, FallbackAvatar, MakeAdmin, Plus, RemoveMembers, Table, User, UserEye} from '@components/Icon/Expensicons'; +import {ReceiptWrangler} from '@components/Icon/Illustrations'; import MessagesRow from '@components/MessagesRow'; import TableListItem from '@components/SelectionList/TableListItem'; import type {ListItem, SelectionListHandle} from '@components/SelectionList/types'; @@ -27,22 +27,33 @@ import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; import usePrevious from '@hooks/usePrevious'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useSearchBackPress from '@hooks/useSearchBackPress'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; -import * as DeviceCapabilities from '@libs/DeviceCapabilities'; -import * as LocalePhoneNumber from '@libs/LocalePhoneNumber'; +import { + clearAddMemberError, + clearDeleteMemberError, + clearInviteDraft, + clearWorkspaceOwnerChangeFlow, + downloadMembersCSV, + isApprover, + openWorkspaceMembersPage, + removeMembers, + updateWorkspaceMembersRole, +} from '@libs/actions/Policy/Member'; +import {canUseTouchScreen} from '@libs/DeviceCapabilities'; +import {formatPhoneNumber as formatPhoneNumberUtil} from '@libs/LocalePhoneNumber'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {FullScreenNavigatorParamList} from '@libs/Navigation/types'; -import * as OptionsListUtils from '@libs/OptionsListUtils'; -import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; -import * as PolicyUtils from '@libs/PolicyUtils'; +import {isPersonalDetailsReady, sortAlphabetically} from '@libs/OptionsListUtils'; +import {getDisplayNameOrDefault, getPersonalDetailsByIDs} from '@libs/PersonalDetailsUtils'; +import {getMemberAccountIDsForWorkspace, isDeletedPolicyEmployee, isExpensifyTeam, isPaidGroupPolicy, isPolicyAdmin as isPolicyAdminUtils} from '@libs/PolicyUtils'; import {getDisplayNameForParticipant} from '@libs/ReportUtils'; -import * as Modal from '@userActions/Modal'; -import * as Member from '@userActions/Policy/Member'; -import * as Policy from '@userActions/Policy/Policy'; +import {close} from '@userActions/Modal'; +import {dismissAddedWithPrimaryLoginMessages} from '@userActions/Policy/Policy'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -69,7 +80,7 @@ function invertObject(object: Record): Record { type MemberOption = Omit & {accountID: number}; function WorkspaceMembersPage({personalDetails, route, policy, currentUserPersonalDetails}: WorkspaceMembersPageProps) { - const policyMemberEmailsToAccountIDs = useMemo(() => PolicyUtils.getMemberAccountIDsForWorkspace(policy?.employeeList, true), [policy?.employeeList]); + const policyMemberEmailsToAccountIDs = useMemo(() => getMemberAccountIDsForWorkspace(policy?.employeeList, true), [policy?.employeeList]); const styles = useThemeStyles(); const [selectedEmployees, setSelectedEmployees] = useState([]); const [removeMembersConfirmModalVisible, setRemoveMembersConfirmModalVisible] = useState(false); @@ -89,9 +100,9 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson // We need to use isSmallScreenWidth instead of shouldUseNarrowLayout to apply the correct modal type for the decision modal // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout(); - const isPolicyAdmin = PolicyUtils.isPolicyAdmin(policy); + const isPolicyAdmin = isPolicyAdminUtils(policy); const isLoading = useMemo( - () => !isOfflineAndNoMemberDataAvailable && (!OptionsListUtils.isPersonalDetailsReady(personalDetails) || isEmptyObject(policy?.employeeList)), + () => !isOfflineAndNoMemberDataAvailable && (!isPersonalDetailsReady(personalDetails) || isEmptyObject(policy?.employeeList)), [isOfflineAndNoMemberDataAvailable, personalDetails, policy?.employeeList], ); @@ -106,11 +117,11 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson const canSelectMultiple = isPolicyAdmin && (shouldUseNarrowLayout ? selectionMode?.isEnabled : true); const confirmModalPrompt = useMemo(() => { - const approverAccountID = selectedEmployees.find((selectedEmployee) => Member.isApprover(policy, selectedEmployee)); + const approverAccountID = selectedEmployees.find((selectedEmployee) => isApprover(policy, selectedEmployee)); if (!approverAccountID) { return translate('workspace.people.removeMembersPrompt', { count: selectedEmployees.length, - memberName: LocalePhoneNumber.formatPhoneNumber(PersonalDetailsUtils.getPersonalDetailsByIDs({accountIDs: selectedEmployees, currentUserAccountID}).at(0)?.displayName ?? ''), + memberName: formatPhoneNumberUtil(getPersonalDetailsByIDs({accountIDs: selectedEmployees, currentUserAccountID}).at(0)?.displayName ?? ''), }); } return translate('workspace.people.removeMembersWarningPrompt', { @@ -133,7 +144,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson * Get members for the current workspace */ const getWorkspaceMembers = useCallback(() => { - Member.openWorkspaceMembersPage(route.params.policyID, Object.keys(PolicyUtils.getMemberAccountIDsForWorkspace(policy?.employeeList))); + openWorkspaceMembersPage(route.params.policyID, Object.keys(getMemberAccountIDsForWorkspace(policy?.employeeList))); }, [route.params.policyID, policy?.employeeList]); /** @@ -179,7 +190,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson return res?.accountID ?? id; }); - const currentSelectedElements = Object.entries(PolicyUtils.getMemberAccountIDsForWorkspace(policy?.employeeList)) + const currentSelectedElements = Object.entries(getMemberAccountIDsForWorkspace(policy?.employeeList)) .filter((employee) => policy?.employeeList?.[employee[0]]?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE) .map((employee) => employee[1]); @@ -201,7 +212,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson * Open the modal to invite a user */ const inviteUser = useCallback(() => { - Member.clearInviteDraft(route.params.policyID); + clearInviteDraft(route.params.policyID); Navigation.navigate(ROUTES.WORKSPACE_INVITE.getRoute(route.params.policyID, Navigation.getActiveRouteWithoutParams())); }, [route.params.policyID]); @@ -219,7 +230,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson setSelectedEmployees([]); setRemoveMembersConfirmModalVisible(false); InteractionManager.runAfterInteractions(() => { - Member.removeMembers(accountIDsToRemove, route.params.policyID); + removeMembers(accountIDsToRemove, route.params.policyID); }); }; @@ -298,11 +309,11 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson /** Opens the member details page */ const openMemberDetails = useCallback( (item: MemberOption) => { - if (!isPolicyAdmin || !PolicyUtils.isPaidGroupPolicy(policy)) { + if (!isPolicyAdmin || !isPaidGroupPolicy(policy)) { Navigation.navigate(ROUTES.PROFILE.getRoute(item.accountID)); return; } - Member.clearWorkspaceOwnerChangeFlow(policyID); + clearWorkspaceOwnerChangeFlow(policyID); Navigation.navigate(ROUTES.WORKSPACE_MEMBER_DETAILS.getRoute(route.params.policyID, item.accountID)); }, [isPolicyAdmin, policy, policyID, route.params.policyID], @@ -314,9 +325,9 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson const dismissError = useCallback( (item: MemberOption) => { if (item.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE) { - Member.clearDeleteMemberError(route.params.policyID, item.accountID); + clearDeleteMemberError(route.params.policyID, item.accountID); } else { - Member.clearAddMemberError(route.params.policyID, item.accountID); + clearAddMemberError(route.params.policyID, item.accountID); } }, [route.params.policyID], @@ -330,7 +341,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson Object.entries(policy?.employeeList ?? {}).forEach(([email, policyEmployee]) => { const accountID = Number(policyMemberEmailsToAccountIDs[email] ?? ''); - if (PolicyUtils.isDeletedPolicyEmployee(policyEmployee, isOffline)) { + if (isDeletedPolicyEmployee(policyEmployee, isOffline)) { return; } @@ -344,8 +355,8 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson // If this policy is owned by Expensify then show all support (expensify.com or team.expensify.com) emails // We don't want to show guides as policy members unless the user is a guide. Some customers get confused when they // see random people added to their policy, but guides having access to the policies help set them up. - if (PolicyUtils.isExpensifyTeam(details?.login ?? details?.displayName)) { - if (policyOwner && currentUserLogin && !PolicyUtils.isExpensifyTeam(policyOwner) && !PolicyUtils.isExpensifyTeam(currentUserLogin)) { + if (isExpensifyTeam(details?.login ?? details?.displayName)) { + if (policyOwner && currentUserLogin && !isExpensifyTeam(policyOwner) && !isExpensifyTeam(currentUserLogin)) { return; } } @@ -371,12 +382,12 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson isDisabled: isPendingDeleteOrError, isInteractive: !details.isOptimisticPersonalDetail, cursorStyle: details.isOptimisticPersonalDetail ? styles.cursorDefault : {}, - text: formatPhoneNumber(PersonalDetailsUtils.getDisplayNameOrDefault(details)), + text: formatPhoneNumber(getDisplayNameOrDefault(details)), alternateText: formatPhoneNumber(details?.login ?? ''), rightElement: roleBadge, icons: [ { - source: details.avatar ?? Expensicons.FallbackAvatar, + source: details.avatar ?? FallbackAvatar, name: formatPhoneNumber(details?.login ?? ''), type: CONST.ICON_TYPE_AVATAR, id: accountID, @@ -388,7 +399,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson invitedSecondaryLogin: details?.login ? invitedPrimaryToSecondaryLogins[details.login] ?? '' : '', }); }); - result = OptionsListUtils.sortAlphabetically(result, 'text'); + result = sortAlphabetically(result, 'text'); return result; }, [ isOffline, @@ -420,7 +431,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson } const invitedEmails = Object.values(invitedEmailsToAccountIDsDraft).map(String); selectionListRef.current?.scrollAndHighlightItem?.(invitedEmails); - Member.clearInviteDraft(route.params.policyID); + clearInviteDraft(route.params.policyID); }, [invitedEmailsToAccountIDsDraft, isFocused, accountIDs, prevAccountIDs, route.params.policyID]); const getHeaderMessage = () => { @@ -440,7 +451,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson // eslint-disable-next-line @typescript-eslint/naming-convention messages={{0: translate('workspace.people.addedWithPrimary')}} containerStyles={[styles.pb5, styles.ph5]} - onClose={() => Policy.dismissAddedWithPrimaryLoginMessages(policyID)} + onClose={() => dismissAddedWithPrimaryLoginMessages(policyID)} /> )} @@ -454,6 +465,11 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson setSelectedEmployees([]); }, [setSelectedEmployees, selectionMode?.isEnabled]); + useSearchBackPress({ + onClearSelection: () => setSelectedEmployees([]), + onNavigationCallBack: () => Navigation.goBack(), + }); + const getCustomListHeader = () => { return ( changeUserRole(CONST.POLICY.ROLE.USER), }; const adminOption = { text: translate('workspace.people.makeAdmin'), value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.MAKE_ADMIN, - icon: Expensicons.MakeAdmin, + icon: MakeAdmin, onSelected: () => changeUserRole(CONST.POLICY.ROLE.ADMIN), }; const auditorOption = { text: translate('workspace.people.makeAuditor'), value: CONST.POLICY.MEMBERS_BULK_ACTION_TYPES.MAKE_AUDITOR, - icon: Expensicons.UserEye, + icon: UserEye, onSelected: () => changeUserRole(CONST.POLICY.ROLE.AUDITOR), }; @@ -557,7 +573,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson success onPress={inviteUser} text={translate('workspace.invite.member')} - icon={Expensicons.Plus} + icon={Plus} innerStyles={[shouldUseNarrowLayout && styles.alignItemsCenter]} style={[shouldUseNarrowLayout && styles.flexGrow1, shouldUseNarrowLayout && styles.mb3]} /> @@ -571,27 +587,27 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson const menuItems = [ { - icon: Expensicons.Table, + icon: Table, text: translate('spreadsheet.importSpreadsheet'), onSelected: () => { if (isOffline) { - Modal.close(() => setIsOfflineModalVisible(true)); + close(() => setIsOfflineModalVisible(true)); return; } Navigation.navigate(ROUTES.WORKSPACE_MEMBERS_IMPORT.getRoute(policyID)); }, }, { - icon: Expensicons.Download, + icon: Download, text: translate('spreadsheet.downloadCSV'), onSelected: () => { if (isOffline) { - Modal.close(() => setIsOfflineModalVisible(true)); + close(() => setIsOfflineModalVisible(true)); return; } - Modal.close(() => { - Member.downloadMembersCSV(policyID, () => { + close(() => { + downloadMembersCSV(policyID, () => { setIsDownloadFailureModalVisible(true); }); }); @@ -609,7 +625,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson headerText={selectionModeHeader ? translate('common.selectMultiple') : translate('workspace.common.members')} route={route} guidesCallTaskID={CONST.GUIDES_CALL_TASK_IDS.WORKSPACE_MEMBERS} - icon={!selectionModeHeader ? Illustrations.ReceiptWrangler : undefined} + icon={!selectionModeHeader ? ReceiptWrangler : undefined} headerContent={!shouldUseNarrowLayout && getHeaderButtons()} testID={WorkspaceMembersPage.displayName} shouldShowLoading={false} @@ -684,7 +700,7 @@ function WorkspaceMembersPage({personalDetails, route, policy, currentUserPerson onSelectAll={() => toggleAllUsers(data)} onDismissError={dismissError} showLoadingPlaceholder={isLoading} - shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} + shouldPreventDefaultFocusOnSelectRow={!canUseTouchScreen()} textInputRef={textInputRef} customListHeader={getCustomListHeader()} listHeaderWrapperStyle={[styles.ph9, styles.pv3, styles.pb5]} diff --git a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx index a773cae02905..fcf01d9df4ef 100644 --- a/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx +++ b/src/pages/workspace/categories/WorkspaceCategoriesPage.tsx @@ -29,6 +29,7 @@ import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; import usePolicy from '@hooks/usePolicy'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useSearchBackPress from '@hooks/useSearchBackPress'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; @@ -104,6 +105,11 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) { setSelectedCategories({}); }, [isFocused]); + useSearchBackPress({ + onClearSelection: () => setSelectedCategories({}), + onNavigationCallBack: () => Navigation.goBack(backTo), + }); + const updateWorkspaceRequiresCategory = useCallback( (value: boolean, categoryName: string) => { setWorkspaceCategoryEnabled(policyId, {[categoryName]: {name: categoryName, enabled: value}}); diff --git a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx index 3c7a969f4057..9936b69ba5d6 100644 --- a/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx +++ b/src/pages/workspace/distanceRates/PolicyDistanceRatesPage.tsx @@ -19,6 +19,7 @@ import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; import usePolicy from '@hooks/usePolicy'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useSearchBackPress from '@hooks/useSearchBackPress'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; @@ -108,6 +109,11 @@ function PolicyDistanceRatesPage({ setSelectedDistanceRates([]); }, [isFocused]); + useSearchBackPress({ + onClearSelection: () => setSelectedDistanceRates([]), + onNavigationCallBack: () => Navigation.goBack(), + }); + const updateDistanceRateEnabled = useCallback( (value: boolean, rateID: string) => { if (!customUnit) { diff --git a/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx b/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx index 1f51af583d8a..5ff8dd9caa29 100644 --- a/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx +++ b/src/pages/workspace/perDiem/WorkspacePerDiemPage.tsx @@ -24,6 +24,7 @@ import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; import usePolicy from '@hooks/usePolicy'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useSearchBackPress from '@hooks/useSearchBackPress'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; @@ -279,6 +280,13 @@ function WorkspacePerDiemPage({route}: WorkspacePerDiemPageProps) { setSelectedPerDiem([]); }, [setSelectedPerDiem, selectionMode?.isEnabled]); + useSearchBackPress({ + onClearSelection: () => { + setSelectedPerDiem([]); + }, + onNavigationCallBack: () => Navigation.goBack(backTo), + }); + const hasVisibleSubRates = subRatesList.some((subRate) => subRate.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || isOffline); const getHeaderText = () => ( diff --git a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx index fa5a911b51c3..2c23f1877523 100644 --- a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx @@ -20,6 +20,7 @@ import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useSearchBackPress from '@hooks/useSearchBackPress'; import useThemeStyles from '@hooks/useThemeStyles'; import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; import { @@ -107,6 +108,13 @@ function ReportFieldsListValuesPage({ [policyID, reportFieldID], ); + useSearchBackPress({ + onClearSelection: () => { + setSelectedValues({}); + }, + onNavigationCallBack: () => Navigation.goBack(), + }); + const listValuesSections = useMemo(() => { const data = listValues .map((value, index) => ({ diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 5602acec4767..298effde4158 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -28,6 +28,7 @@ import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; import usePolicy from '@hooks/usePolicy'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useSearchBackPress from '@hooks/useSearchBackPress'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; @@ -101,6 +102,13 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) { setSelectedTags({}); }, [isFocused]); + useSearchBackPress({ + onClearSelection: () => { + setSelectedTags({}); + }, + onNavigationCallBack: () => Navigation.goBack(backTo), + }); + const getPendingAction = (policyTagList: PolicyTagList): PendingAction | undefined => { if (!policyTagList) { return undefined; diff --git a/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx b/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx index 6f54a36d92b8..f378e9c29e65 100644 --- a/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx @@ -19,6 +19,7 @@ import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; import usePolicy from '@hooks/usePolicy'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useSearchBackPress from '@hooks/useSearchBackPress'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode'; @@ -88,6 +89,13 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) { }; }, [isFocused]); + useSearchBackPress({ + onClearSelection: () => { + setSelectedTags({}); + }, + onNavigationCallBack: () => Navigation.goBack(isQuickSettingsFlow ? ROUTES.SETTINGS_TAGS_ROOT.getRoute(policyID) : undefined), + }); + const updateWorkspaceTagEnabled = useCallback( (value: boolean, tagName: string) => { setWorkspaceTagEnabled(policyID, {[tagName]: {name: tagName, enabled: value}}, route.params.orderWeight); diff --git a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx index 8e8696afb1d2..a72d2206fae9 100644 --- a/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx +++ b/src/pages/workspace/taxes/WorkspaceTaxesPage.tsx @@ -22,6 +22,7 @@ import useLocalize from '@hooks/useLocalize'; import useMobileSelectionMode from '@hooks/useMobileSelectionMode'; import useNetwork from '@hooks/useNetwork'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useSearchBackPress from '@hooks/useSearchBackPress'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import {isConnectionInProgress} from '@libs/actions/connections'; @@ -93,6 +94,13 @@ function WorkspaceTaxesPage({ setSelectedTaxesIDs([]); }, [isFocused]); + useSearchBackPress({ + onClearSelection: () => { + setSelectedTaxesIDs([]); + }, + onNavigationCallBack: () => Navigation.goBack(), + }); + const textForDefault = useCallback( (taxID: string, taxRate: TaxRate): string => { let suffix;