Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 5 additions & 2 deletions src/components/MigratedUserWelcomeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {MigratedUserModalNavigatorParamList} from '@libs/Navigation/types';
import {buildCannedSearchQuery} from '@libs/SearchQueryUtils';
import {getDefaultActionableSearchMenuItem} from '@libs/SearchUIUtils';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
Expand All @@ -27,7 +28,7 @@
import type {FeatureListItem} from './FeatureList';
import FeatureTrainingModal from './FeatureTrainingModal';
import Icon from './Icon';
import * as Illustrations from './Icon/Illustrations';

Check warning on line 31 in src/components/MigratedUserWelcomeModal.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

'./Icon/Illustrations' import is restricted from being used by a pattern. Direct imports from Icon/Illustrations are deprecated. Please use lazy loading hooks instead. Use `useMemoizedLazyIllustrations` from @hooks/useLazyAsset. See docs/LAZY_ICONS_AND_ILLUSTRATIONS.md for details
import LottieAnimations from './LottieAnimations';
import RenderHTML from './RenderHTML';

Expand Down Expand Up @@ -58,7 +59,7 @@
translationKey: 'migratedUserWelcomeModal.features.chat',
},
],
[illustrations.ExpensifyMobileApp],

Check warning on line 62 in src/components/MigratedUserWelcomeModal.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

React Hook useMemo has an unnecessary dependency: 'illustrations.ExpensifyMobileApp'. Either exclude it or remove the dependency array

Check warning on line 62 in src/components/MigratedUserWelcomeModal.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

React Hook useMemo has an unnecessary dependency: 'illustrations.ExpensifyMobileApp'. Either exclude it or remove the dependency array
);

const [tryNewDot, tryNewDotMetadata] = useOnyx(ONYXKEYS.NVP_TRY_NEW_DOT, {
Expand All @@ -84,8 +85,10 @@

Log.hmmm('[MigratedUserWelcomeModal] Enabling modal and navigating to search');
setIsModalDisabled(false);
const nonExploreTypeQuery = typeMenuSections.at(0)?.menuItems.at(0)?.searchQuery;
Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query: nonExploreTypeQuery ?? buildCannedSearchQuery()}));
const flattenedMenuItems = typeMenuSections.flatMap((section) => section.menuItems);
const defaultActionableSearchQuery =
getDefaultActionableSearchMenuItem(flattenedMenuItems)?.searchQuery ?? flattenedMenuItems.at(0)?.searchQuery ?? typeMenuSections.at(0)?.menuItems.at(0)?.searchQuery;
Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query: defaultActionableSearchQuery ?? buildCannedSearchQuery()}));
}, [dismissedProductTraining?.migratedUserWelcomeModal, setIsModalDisabled, tryNewDotMetadata, dismissedProductTrainingMetadata, tryNewDot, shouldOpenSearch, typeMenuSections]);

return (
Expand Down
11 changes: 9 additions & 2 deletions src/components/Navigation/NavigationTabBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import navigateToWorkspacesPage, {getWorkspaceNavigationRouteState} from '@libs/Navigation/helpers/navigateToWorkspacesPage';
import Navigation from '@libs/Navigation/Navigation';
import {buildCannedSearchQuery, buildSearchQueryJSON, buildSearchQueryString} from '@libs/SearchQueryUtils';
import {getDefaultActionableSearchMenuItem} from '@libs/SearchUIUtils';
import {startSpan} from '@libs/telemetry/activeSpans';
import type {BrickRoad} from '@libs/WorkspacesSettingsUtils';
import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils';
Expand Down Expand Up @@ -164,6 +165,8 @@
Navigation.navigate(ROUTES.HOME);
}, [selectedTab]);

const [lastSearchParams] = useOnyx(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, {canBeMissing: true});

const navigateToSearch = useCallback(() => {
if (selectedTab === NAVIGATION_TABS.SEARCH) {
return;
Expand Down Expand Up @@ -200,11 +203,15 @@
}
}

const nonExploreTypeQuery = typeMenuSections.at(0)?.menuItems.at(0)?.searchQuery;
const flattenedMenuItems = typeMenuSections.flatMap((section) => section.menuItems);
const defaultActionableSearchQuery =
getDefaultActionableSearchMenuItem(flattenedMenuItems)?.searchQuery ?? flattenedMenuItems.at(0)?.searchQuery ?? typeMenuSections.at(0)?.menuItems.at(0)?.searchQuery;

const savedSearchQuery = Object.values(savedSearches ?? {}).at(0)?.query;
Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query: nonExploreTypeQuery ?? savedSearchQuery ?? buildCannedSearchQuery()}));
const lastQueryFromOnyx = lastSearchParams?.queryJSON ? buildSearchQueryString(lastSearchParams.queryJSON) : undefined;
Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query: lastQueryFromOnyx ?? defaultActionableSearchQuery ?? savedSearchQuery ?? buildCannedSearchQuery()}));
});
Comment thread
JS00001 marked this conversation as resolved.
}, [selectedTab, typeMenuSections, savedSearches]);

Check warning on line 214 in src/components/Navigation/NavigationTabBar/index.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

React Hook useCallback has a missing dependency: 'lastSearchParams.queryJSON'. Either include it or remove the dependency array

Check warning on line 214 in src/components/Navigation/NavigationTabBar/index.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

React Hook useCallback has a missing dependency: 'lastSearchParams.queryJSON'. Either include it or remove the dependency array

const navigateToSettings = useCallback(() => {
if (selectedTab === NAVIGATION_TABS.SETTINGS) {
Expand Down
10 changes: 8 additions & 2 deletions src/components/Search/SearchAutocompleteList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,13 @@ function SearchAutocompleteList({

const onArrowFocus = useCallback(
(focusedItem: OptionData | SearchQueryItem) => {
if (!isSearchQueryItem(focusedItem) || !focusedItem.searchQuery || focusedItem?.searchItemType !== CONST.SEARCH.SEARCH_ROUTER_ITEM_TYPE.AUTOCOMPLETE_SUGGESTION) {
if (
isInitialRender ||
!autocompleteQueryValue.trim() ||
!isSearchQueryItem(focusedItem) ||
!focusedItem.searchQuery ||
focusedItem?.searchItemType !== CONST.SEARCH.SEARCH_ROUTER_ITEM_TYPE.AUTOCOMPLETE_SUGGESTION
) {
return;
}

Expand Down Expand Up @@ -830,7 +836,7 @@ function SearchAutocompleteList({
setTextQuery(`${trimmedUserSearchQuery}${sanitizeSearchValue(focusedItem.searchQuery)}\u00A0`);
updateAutocompleteSubstitutions(focusedItem);
},
[autocompleteQueryValue, setTextQuery, updateAutocompleteSubstitutions],
[autocompleteQueryValue, setTextQuery, updateAutocompleteSubstitutions, isInitialRender],
);

const sectionItemText = sections?.at(1)?.data?.[0]?.text ?? '';
Expand Down
9 changes: 8 additions & 1 deletion src/components/Search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ function Search({
const transactionKeys = Object.keys(searchResults.data).filter((key) => key.startsWith(ONYXKEYS.COLLECTION.TRANSACTION));

for (const key of transactionKeys) {
// eslint-disable-next-line @typescript-eslint/no-deprecated
// eslint-disable-next-line
const transaction = searchResults.data[key as keyof typeof searchResults.data] as SearchTransaction;
if (!transaction || typeof transaction !== 'object' || !('transactionID' in transaction) || !('reportID' in transaction)) {
continue;
Expand Down Expand Up @@ -378,6 +378,13 @@ function Search({
openSearch();
}, []);

useEffect(() => {
if (!prevIsOffline || isOffline) {
return;
}
openSearch();
}, [isOffline, prevIsOffline]);

const {newSearchResultKeys, handleSelectionListScroll, newTransactions} = useSearchHighlightAndScroll({
searchResults,
transactions,
Expand Down
7 changes: 5 additions & 2 deletions src/hooks/useOnboardingFlow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {startOnboardingFlow} from '@libs/actions/Welcome/OnboardingFlow';
import getCurrentUrl from '@libs/Navigation/currentUrl';
import Navigation, {navigationRef} from '@libs/Navigation/Navigation';
import {buildCannedSearchQuery} from '@libs/SearchQueryUtils';
import {getDefaultActionableSearchMenuItem} from '@libs/SearchUIUtils';
import {isLoggingInAsNewUser} from '@libs/SessionUtils';
import isProductTrainingElementDismissed from '@libs/TooltipUtils';
import CONFIG from '@src/CONFIG';
Expand Down Expand Up @@ -94,8 +95,10 @@ function useOnboardingFlowRouter() {
const lastRoute = navigationState.routes.at(-1);
// Prevent duplicate navigation if the migrated user modal is already shown.
if (lastRoute?.name !== NAVIGATORS.MIGRATED_USER_MODAL_NAVIGATOR) {
const nonExploreTypeQuery = typeMenuSections.at(0)?.menuItems.at(0)?.searchQuery;
Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query: nonExploreTypeQuery ?? buildCannedSearchQuery()}));
const flattenedMenuItems = typeMenuSections.flatMap((section) => section.menuItems);
const defaultActionableSearchQuery =
getDefaultActionableSearchMenuItem(flattenedMenuItems)?.searchQuery ?? flattenedMenuItems.at(0)?.searchQuery ?? typeMenuSections.at(0)?.menuItems.at(0)?.searchQuery;
Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query: defaultActionableSearchQuery ?? buildCannedSearchQuery()}));
Navigation.navigate(ROUTES.MIGRATED_USER_WELCOME_MODAL.getRoute(true));
}
return;
Expand Down
16 changes: 13 additions & 3 deletions src/hooks/useSearchTypeMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react';
import type {OnyxCollection} from 'react-native-onyx';
import {usePersonalDetails} from '@components/OnyxListItemProvider';
import type {PopoverMenuItem} from '@components/PopoverMenu';
import {useSearchContext} from '@components/Search/SearchContext';
import type {SearchQueryJSON} from '@components/Search/types';
import ThreeDotsMenu from '@components/ThreeDotsMenu';
import {clearAllFilters} from '@libs/actions/Search';
Expand All @@ -24,6 +25,7 @@ import useLocalize from './useLocalize';
import useOnyx from './useOnyx';
import useSearchTypeMenuSections from './useSearchTypeMenuSections';
import useSingleExecution from './useSingleExecution';
import useSuggestedSearchDefaultNavigation from './useSuggestedSearchDefaultNavigation';
import useTheme from './useTheme';
import useThemeStyles from './useThemeStyles';
import useWindowDimensions from './useWindowDimensions';
Expand All @@ -36,7 +38,8 @@ export default function useSearchTypeMenu(queryJSON: SearchQueryJSON) {
const {singleExecution} = useSingleExecution();
const {windowHeight} = useWindowDimensions();
const {translate} = useLocalize();
const {typeMenuSections} = useSearchTypeMenuSections();
const {typeMenuSections, shouldShowSuggestedSearchSkeleton} = useSearchTypeMenuSections();
const {clearSelectedTransactions} = useSearchContext();
const {showDeleteModal, DeleteConfirmModal} = useDeleteSavedSearch();
const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {canBeMissing: true});
const personalDetails = usePersonalDetails();
Expand All @@ -52,6 +55,14 @@ export default function useSearchTypeMenu(queryJSON: SearchQueryJSON) {

const allCards = useMemo(() => mergeCardListWithWorkspaceFeeds(workspaceCardFeeds ?? CONST.EMPTY_OBJECT, userCardList), [userCardList, workspaceCardFeeds]);
const [allFeeds] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER, {canBeMissing: true});
const flattenedMenuItems = useMemo(() => typeMenuSections.flatMap((section) => section.menuItems), [typeMenuSections]);

useSuggestedSearchDefaultNavigation({
shouldShowSkeleton: shouldShowSuggestedSearchSkeleton,
flattenedMenuItems,
similarSearchHash,
clearSelectedTransactions,
});

// this is a performance fix, rendering popover menu takes a lot of time and we don't need this component initially, that's why we postpone rendering it until everything else is rendered
const [delayPopoverMenuFirstRender, setDelayPopoverMenuFirstRender] = useState(true);
Expand Down Expand Up @@ -132,9 +143,8 @@ export default function useSearchTypeMenu(queryJSON: SearchQueryJSON) {
return -1;
}

const flattenedMenuItems = typeMenuSections.map((section) => section.menuItems).flat();
return flattenedMenuItems.findIndex((item) => item.similarSearchHash === similarSearchHash);
}, [similarSearchHash, isSavedSearchActive, typeMenuSections]);
}, [similarSearchHash, isSavedSearchActive, flattenedMenuItems]);

const popoverMenuItems = useMemo(() => {
return typeMenuSections
Expand Down
12 changes: 11 additions & 1 deletion src/hooks/useSearchTypeMenuSections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ const useSearchTypeMenuSections = () => {
openCreateReportConfirmation();
}, [pendingReportCreation, openCreateReportConfirmation]);

const isSuggestedSearchDataReady = useMemo(() => {
const policiesList = Object.values(allPolicies ?? {}).filter((policy): policy is NonNullable<typeof policy> => policy !== null && policy !== undefined);

return policiesList.some((policy) => policy.employeeList !== undefined && policy.exporter !== undefined);
}, [allPolicies]);

const typeMenuSections = useMemo(
() =>
createTypeMenuSections(
Expand Down Expand Up @@ -149,7 +155,11 @@ const useSearchTypeMenuSections = () => {
],
);

return {typeMenuSections, CreateReportConfirmationModal};
return {
typeMenuSections,
CreateReportConfirmationModal,
shouldShowSuggestedSearchSkeleton: !isSuggestedSearchDataReady && !isOffline,
};
};

export default useSearchTypeMenuSections;
42 changes: 42 additions & 0 deletions src/hooks/useSuggestedSearchDefaultNavigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {useEffect, useRef} from 'react';
import {clearAllFilters} from '@libs/actions/Search';
import Navigation from '@libs/Navigation/Navigation';
import type {SearchTypeMenuItem} from '@libs/SearchUIUtils';
import {getDefaultActionableSearchMenuItem} from '@libs/SearchUIUtils';
import ROUTES from '@src/ROUTES';

type UseSuggestedSearchDefaultNavigationParams = {
shouldShowSkeleton: boolean;
flattenedMenuItems: SearchTypeMenuItem[];
similarSearchHash?: number;
clearSelectedTransactions: () => void;
};

function useSuggestedSearchDefaultNavigation({shouldShowSkeleton, flattenedMenuItems, similarSearchHash, clearSelectedTransactions}: UseSuggestedSearchDefaultNavigationParams) {
const hasShownSkeleton = useRef(false);

useEffect(() => {
if (shouldShowSkeleton) {
hasShownSkeleton.current = true;
return;
}

if (!hasShownSkeleton.current) {
return;
}

hasShownSkeleton.current = false;

const defaultMenuItem = getDefaultActionableSearchMenuItem(flattenedMenuItems);

if (!defaultMenuItem || similarSearchHash === defaultMenuItem.similarSearchHash) {
return;
}

clearAllFilters();
clearSelectedTransactions();
Navigation.navigate(ROUTES.SEARCH_ROOT.getRoute({query: defaultMenuItem.searchQuery}));
}, [shouldShowSkeleton, flattenedMenuItems, similarSearchHash, clearSelectedTransactions]);
}

export default useSuggestedSearchDefaultNavigation;
5 changes: 5 additions & 0 deletions src/libs/SearchUIUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,10 @@ function getSuggestedSearches(
};
}

function getDefaultActionableSearchMenuItem(menuItems: SearchTypeMenuItem[]) {
return menuItems.find((item) => item.key === CONST.SEARCH.SEARCH_KEYS.APPROVE) ?? menuItems.find((item) => item.key === CONST.SEARCH.SEARCH_KEYS.SUBMIT);
}

function getSuggestedSearchesVisibility(
currentUserEmail: string | undefined,
cardFeedsByPolicy: Record<string, CardFeedForDisplay[]>,
Expand Down Expand Up @@ -2598,6 +2602,7 @@ function getColumnsToShow(

export {
getSuggestedSearches,
getDefaultActionableSearchMenuItem,
getListItem,
getSections,
getSuggestedSearchesVisibility,
Expand Down
Loading
Loading