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
1 change: 1 addition & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1794,6 +1794,7 @@ const CONST = {
SPAN_SEARCH_ROUTER_OPTIONS_INIT: 'SearchRouter.OptionsInit',
SPAN_SEARCH_ROUTER_COMPUTE_OPTIONS: 'SearchRouter.ComputeOptions',
SPAN_SEARCH_ROUTER_LIST_RENDER: 'SearchRouter.ListRender',
SPAN_SEARCH_PAGE_VISIBLE: 'ManualOpenSearchRouterPageVisible',
SPAN_OPEN_CREATE_EXPENSE: 'ManualOpenCreateExpense',
SPAN_CAMERA_INIT: 'ManualCameraInit',
SPAN_SHUTTER_TO_CONFIRMATION: 'ManualShutterToConfirmation',
Expand Down
13 changes: 12 additions & 1 deletion src/components/OptionsListSkeletonView.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import type {LayoutChangeEvent} from 'react-native';
import {Circle} from 'react-native-svg';
import useThemeStyles from '@hooks/useThemeStyles';
import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan';
Expand Down Expand Up @@ -26,9 +27,18 @@ type OptionsListSkeletonViewProps = {
fixedNumItems?: number;
speed?: number;
reasonAttributes?: SkeletonSpanReasonAttributes;
onLayout?: (event: LayoutChangeEvent) => void;
};

function OptionsListSkeletonView({shouldAnimate = true, shouldStyleAsTable = false, gradientOpacityEnabled = false, fixedNumItems, speed, reasonAttributes}: OptionsListSkeletonViewProps) {
function OptionsListSkeletonView({
shouldAnimate = true,
shouldStyleAsTable = false,
gradientOpacityEnabled = false,
fixedNumItems,
speed,
reasonAttributes,
onLayout,
}: OptionsListSkeletonViewProps) {
const styles = useThemeStyles();
useSkeletonSpan('OptionsListSkeletonView', reasonAttributes);

Expand All @@ -37,6 +47,7 @@ function OptionsListSkeletonView({shouldAnimate = true, shouldStyleAsTable = fal
fixedNumItems={fixedNumItems}
speed={speed}
shouldAnimate={shouldAnimate}
onLayout={onLayout}
style={[styles.overflowHidden]}
itemViewStyle={shouldStyleAsTable && [styles.highlightBG, styles.mb2, styles.ml5, styles.br2]}
gradientOpacityEnabled={gradientOpacityEnabled}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React, {useCallback, useRef} from 'react';
import OptionsListSkeletonView from '@components/OptionsListSkeletonView';
import type {SearchAutocompleteListProps} from '@components/Search/SearchAutocompleteList';
import SearchAutocompleteList from '@components/Search/SearchAutocompleteList';
import {endSpan} from '@libs/telemetry/activeSpans';
import CONST from '@src/CONST';

/**
* This component acts as a wrapper for a SearchAutocompleteList, waiting for the navigation to be ready and deferring it,
* so that the base UI can render before the list is loaded.
* This enables the SearchRouterPage to open smoothly with a placeholder and load the list in the meantime.
*/
function DeferredAutocompleteList(props: SearchAutocompleteListProps) {
const [shouldRender, setShouldRender] = React.useState(false);
const [, startTransition] = React.useTransition();
const hasEndedPageVisibleSpan = useRef(false);

// Run the transition after the skeleton is mounted; end the "page visible" span once
const renderComponent = useCallback(() => {
if (!hasEndedPageVisibleSpan.current) {
hasEndedPageVisibleSpan.current = true;
endSpan(CONST.TELEMETRY.SPAN_SEARCH_PAGE_VISIBLE);
}
startTransition(() => setShouldRender(true));
}, []);

if (!shouldRender) {
return (
<OptionsListSkeletonView
fixedNumItems={4}
shouldStyleAsTable
onLayout={renderComponent}
speed={CONST.TIMING.SKELETON_ANIMATION_SPEED}
/>
);
}

// eslint-disable-next-line react/jsx-props-no-spreading -- This is a transparent wrapper that forwards all props to SearchAutocompleteList
return <SearchAutocompleteList {...props} />;
}

DeferredAutocompleteList.displayName = 'DeferredSearchAutocompleteList';

export default DeferredAutocompleteList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* The rendering is fast enough for the web, so only a native implementation is required. See index.native.ts.
*/
import SearchAutocompleteList from '@components/Search/SearchAutocompleteList';

export default SearchAutocompleteList;
2 changes: 1 addition & 1 deletion src/components/Search/SearchAutocompleteList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@
}, [autocompleteQueryWithoutFilters, debounceHandleSearch]);

/* Sections generation */
const sections: Array<Section<AutocompleteListItem>> = [];

Check warning on line 358 in src/components/Search/SearchAutocompleteList.tsx

View workflow job for this annotation

GitHub Actions / ESLint check

The 'sections' array makes the dependencies of useEffect Hook (at line 440) change on every render. To fix this, wrap the initialization of 'sections' in its own useMemo() Hook

Check warning on line 358 in src/components/Search/SearchAutocompleteList.tsx

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

The 'sections' array makes the dependencies of useEffect Hook (at line 440) change on every render. To fix this, wrap the initialization of 'sections' in its own useMemo() Hook
let sectionIndex = 0;

if (searchQueryItem) {
Expand Down Expand Up @@ -504,4 +504,4 @@

export default React.memo(SearchAutocompleteList);
export {SearchRouterItem};
export type {GetAdditionalSectionsCallback};
export type {GetAdditionalSectionsCallback, SearchAutocompleteListProps};
3 changes: 3 additions & 0 deletions src/components/Search/SearchRouter/SearchButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {startSpan} from '@libs/telemetry/activeSpans';
import {callFunctionIfActionIsAllowed} from '@userActions/Session';
import CONST from '@src/CONST';
import {useSearchRouterActions} from './SearchRouterContext';
import startSearchPageVisibleSpan from './startSearchPageVisibleSpan';

type SearchButtonProps = {
style?: StyleProp<ViewStyle>;
Expand All @@ -37,6 +38,8 @@ function SearchButton({style, shouldUseAutoHitSlop = false}: SearchButtonProps)
},
});

startSearchPageVisibleSpan();

openSearchRouter();
})();
};
Expand Down
4 changes: 2 additions & 2 deletions src/components/Search/SearchRouter/SearchRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import type {ValueOf} from 'type-fest';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import {usePersonalDetails} from '@components/OnyxListItemProvider';
import type {AnimatedTextInputRef} from '@components/RNTextInput';
import DeferredAutocompleteList from '@components/Search/DeferredSearchAutocompleteList';
import type {GetAdditionalSectionsCallback} from '@components/Search/SearchAutocompleteList';
import SearchAutocompleteList from '@components/Search/SearchAutocompleteList';
import {useSearchActionsContext} from '@components/Search/SearchContext';
import SearchInputSelectionWrapper from '@components/Search/SearchInputSelectionWrapper';
import type {SearchQueryString} from '@components/Search/types';
Expand Down Expand Up @@ -344,7 +344,7 @@ function SearchRouter({onRouterClose, shouldHideInputCaret, isSearchRouterDispla
shouldDelayFocus
/>
</View>
<SearchAutocompleteList
<DeferredAutocompleteList
autocompleteQueryValue={autocompleteQueryValue || textInputValue}
handleSearch={searchInServer}
searchQueryItem={searchQueryItem}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, {useContext, useEffect, useRef, useState} from 'react';
import type {AnimatedTextInputRef} from '@components/RNTextInput';
import isSearchTopmostFullScreenRoute from '@libs/Navigation/helpers/isSearchTopmostFullScreenRoute';
import {navigationRef} from '@libs/Navigation/Navigation';
import {endSpan, getSpan, startSpan} from '@libs/telemetry/activeSpans';
import {cancelSpan, endSpan, getSpan, startSpan} from '@libs/telemetry/activeSpans';
import {close} from '@userActions/Modal';
import CONST from '@src/CONST';
import NAVIGATORS from '@src/NAVIGATORS';
Expand Down Expand Up @@ -94,6 +94,7 @@ function SearchRouterContextProvider({children}: ChildrenProps) {
};

const closeSearchRouter = () => {
cancelSpan(CONST.TELEMETRY.SPAN_SEARCH_PAGE_VISIBLE);
closeSearch(setIsSearchRouterDisplayed);
searchRouterDisplayedRef.current = false;
if (isBrowserWithHistory) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {startSpan} from '@libs/telemetry/activeSpans';
import CONST from '@src/CONST';

function startSearchPageVisibleSpan() {
startSpan(CONST.TELEMETRY.SPAN_SEARCH_PAGE_VISIBLE, {
name: CONST.TELEMETRY.SPAN_SEARCH_PAGE_VISIBLE,
op: CONST.TELEMETRY.SPAN_SEARCH_PAGE_VISIBLE,
});
}

export default startSearchPageVisibleSpan;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function startSearchPageVisibleSpan() {
// Do not start span on the web
}

export default startSearchPageVisibleSpan;
6 changes: 5 additions & 1 deletion src/components/Skeletons/ItemListSkeletonView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type ListItemSkeletonProps = {
itemViewHeight?: number;
speed?: number;
style?: StyleProp<ViewStyle>;
onLayout?: (event: LayoutChangeEvent) => void;
};

const getVerticalMargin = (style: StyleProp<ViewStyle>): number => {
Expand All @@ -39,6 +40,7 @@ function ItemListSkeletonView({
itemViewHeight = CONST.LHN_SKELETON_VIEW_ITEM_HEIGHT,
speed,
style,
onLayout,
}: ListItemSkeletonProps) {
const theme = useTheme();
const themeStyles = useThemeStyles();
Expand All @@ -49,6 +51,8 @@ function ItemListSkeletonView({

const handleLayout = useCallback(
(event: LayoutChangeEvent) => {
onLayout?.(event);

if (fixedNumItems) {
return;
}
Expand All @@ -59,7 +63,7 @@ function ItemListSkeletonView({
setNumItems(newNumItems);
}
},
[fixedNumItems, numItems, totalItemHeight],
[fixedNumItems, numItems, onLayout, totalItemHeight],
);

const skeletonViewItems = useMemo(() => {
Expand Down
Loading