mirror of
https://github.com/inaturalist/iNaturalistReactNative.git
synced 2026-10-06 10:02:33 -04:00
Merge pull request #3771 from inaturalist/mob-1462-search-myobs-ui-2
Mob 1462 search myobs UI 2
This commit is contained in:
16 files changed
+251
-21
No files matched your search
@@ -46,10 +46,10 @@ const AddObsButton = ( ): React.Node => {
|
||||
// Base trigger condition in all cases:
|
||||
// Only show the tooltip if the user has the AI camera as the default button option.
|
||||
// Only show the tooltip on MyObservations screen.
|
||||
const onObsList = currentRoute?.name === "MyObservationsResults";
|
||||
const isOnMyObservationsResults = currentRoute?.name === "MyObservationsResults";
|
||||
const onlyAiCamera = !isAllAddObsOptionsMode;
|
||||
|
||||
let triggerCondition = onObsList && onlyAiCamera;
|
||||
let triggerCondition = isOnMyObservationsResults && onlyAiCamera;
|
||||
|
||||
if ( justFinishedSignup ) {
|
||||
// If a user creates a new account, they should see the tooltip right after dismissing the
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import classnames from "classnames";
|
||||
import {
|
||||
BackButton,
|
||||
Body3,
|
||||
Heading4,
|
||||
} from "components/SharedComponents";
|
||||
import { View } from "components/styledComponents";
|
||||
import { Pressable, View } from "components/styledComponents";
|
||||
import React from "react";
|
||||
import { useTranslation } from "sharedHooks";
|
||||
|
||||
@@ -11,6 +12,7 @@ interface Props {
|
||||
closeModal: ( ) => void;
|
||||
headerText: string;
|
||||
resetFilters: ( ) => void;
|
||||
resetDisabled?: boolean;
|
||||
testID: string;
|
||||
}
|
||||
|
||||
@@ -18,6 +20,7 @@ const ExploreSearchHeader = ( {
|
||||
closeModal,
|
||||
headerText,
|
||||
resetFilters,
|
||||
resetDisabled = false,
|
||||
testID,
|
||||
}: Props ) => {
|
||||
const { t } = useTranslation( );
|
||||
@@ -32,11 +35,21 @@ const ExploreSearchHeader = ( {
|
||||
/>
|
||||
</View>
|
||||
<Heading4 className="flex-1 wrap text-center">{headerText}</Heading4>
|
||||
<View className="w-[50px] items-end">
|
||||
<Body3 onPress={resetFilters} maxFontSizeMultiplier={1.5}>
|
||||
<Pressable
|
||||
className={classnames(
|
||||
"w-[50px] items-end",
|
||||
{ "opacity-50": resetDisabled },
|
||||
)}
|
||||
onPress={resetFilters}
|
||||
disabled={resetDisabled}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={t( "Reset-verb" )}
|
||||
testID={`${testID}.reset`}
|
||||
>
|
||||
<Body3 maxFontSizeMultiplier={1.5}>
|
||||
{t( "Reset-verb" )}
|
||||
</Body3>
|
||||
</View>
|
||||
</Pressable>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -35,6 +35,8 @@ import {
|
||||
} from "sharedHelpers/speciesSort";
|
||||
import { accessibleTaxonName } from "sharedHelpers/taxon";
|
||||
import { useGridLayout, useLayoutPrefs, useTranslation } from "sharedHooks";
|
||||
import useFeatureFlag from "sharedHooks/useFeatureFlag";
|
||||
import { FeatureFlag } from "stores/createFeatureFlagSlice";
|
||||
import colors from "styles/tailwindColors";
|
||||
import type { SpeciesCount } from "types/sorting";
|
||||
|
||||
@@ -42,6 +44,7 @@ import LoginSheet from "./LoginSheet";
|
||||
import { ACTIVE_SHEET } from "./MyObservationsResults";
|
||||
import MyObservationsSimpleHeader from "./MyObservationsSimpleHeader";
|
||||
import PivotCardObsGridItem from "./PivotCardObsGridItem";
|
||||
import SearchedTaxonBanner from "./Search/SearchedTaxonBanner";
|
||||
import SimpleHeader from "./SimpleHeader";
|
||||
import SimpleTaxonGridItem from "./SimpleTaxonGridItem";
|
||||
|
||||
@@ -131,6 +134,9 @@ const MyObservationsSimple = ( {
|
||||
}: Props ) => {
|
||||
const { isDefaultMode } = useLayoutPrefs( );
|
||||
const { t } = useTranslation( );
|
||||
const searchMyObservationsEnabled = useFeatureFlag(
|
||||
FeatureFlag.SearchMyObservationsEnabled,
|
||||
);
|
||||
const speciesSortLabels = useSpeciesSortLabels( );
|
||||
const navigation = useNavigation( );
|
||||
const route = useRoute( );
|
||||
@@ -358,6 +364,9 @@ const MyObservationsSimple = ( {
|
||||
]}
|
||||
TabComponent={renderTabComponent}
|
||||
/>
|
||||
{searchMyObservationsEnabled && activeTab === OBSERVATIONS_TAB && (
|
||||
<SearchedTaxonBanner />
|
||||
)}
|
||||
{ activeTab === OBSERVATIONS_TAB && (
|
||||
<>
|
||||
<ObservationsFlashList
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
SCREEN_NAME_SEARCH_MY_OBSERVATIONS,
|
||||
} from "navigation/StackNavigators/MyObservationsStackNavigator";
|
||||
import type { MyObservationsStackScreenProps } from "navigation/types";
|
||||
import { useMyObservations } from "providers/MyObservationsContext";
|
||||
import React from "react";
|
||||
import { Alert } from "react-native";
|
||||
import type {
|
||||
@@ -51,6 +52,8 @@ const MyObservationsSimpleHeader = ( {
|
||||
const searchMyObservationsEnabled = useFeatureFlag(
|
||||
FeatureFlag.SearchMyObservationsEnabled,
|
||||
);
|
||||
const { state: myObsState } = useMyObservations( );
|
||||
const searchActive = myObsState.searchedTaxon !== null;
|
||||
|
||||
const handleSearchButtonPress = ( ) => {
|
||||
if ( !isConnected ) {
|
||||
@@ -111,6 +114,9 @@ const MyObservationsSimpleHeader = ( {
|
||||
<INatIconButton
|
||||
icon="magnifying-glass"
|
||||
onPress={handleSearchButtonPress}
|
||||
color={searchActive
|
||||
? colors.inatGreen
|
||||
: colors.darkGray}
|
||||
accessibilityLabel={t( "Opens-search-interface" )}
|
||||
size={20}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// TODO: This component is intentionally not rendered anywhere yet.
|
||||
// This is the empty state for the Search My Observations feature.
|
||||
|
||||
import {
|
||||
Body1,
|
||||
Button,
|
||||
} from "components/SharedComponents";
|
||||
import { View } from "components/styledComponents";
|
||||
import {
|
||||
MY_OBSERVATIONS_ACTION,
|
||||
useMyObservations,
|
||||
} from "providers/MyObservationsContext";
|
||||
import React from "react";
|
||||
import { useTranslation } from "sharedHooks";
|
||||
|
||||
const SearchEmptyState = ( ) => {
|
||||
const { t } = useTranslation( );
|
||||
const { dispatch } = useMyObservations( );
|
||||
|
||||
return (
|
||||
<View className="flex-1 px-5 items-center justify-center">
|
||||
<Body1 className="text-center mb-6">
|
||||
{t( "Looks-like-you-havent-observed-this-yet-time-to-keep-exploring" )}
|
||||
</Body1>
|
||||
<Button
|
||||
level="focus"
|
||||
className="w-full"
|
||||
text={t( "RESET-SEARCH" )}
|
||||
onPress={( ) => dispatch( {
|
||||
type: MY_OBSERVATIONS_ACTION.CLEAR_TAXON_SEARCH,
|
||||
} )}
|
||||
testID="MyObservationsSearchEmptyState.reset"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchEmptyState;
|
||||
@@ -14,14 +14,23 @@ import {
|
||||
useMyObservations,
|
||||
} from "providers/MyObservationsContext";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useTranslation } from "sharedHooks";
|
||||
import type { RealmTaxon, RealmUser } from "realmModels/types";
|
||||
import { taxonDisplayName } from "sharedHelpers/taxon";
|
||||
import { useCurrentUser, useTranslation } from "sharedHooks";
|
||||
import useTaxonSearch from "sharedHooks/useTaxonSearch";
|
||||
|
||||
const SearchMyObservationsTaxon = ( ) => {
|
||||
const { t } = useTranslation( );
|
||||
const navigation = useNavigation( );
|
||||
const { dispatch } = useMyObservations( );
|
||||
const [taxonQuery, setTaxonQuery] = useState( "" );
|
||||
const { state, dispatch } = useMyObservations( );
|
||||
const { searchedTaxon } = state;
|
||||
const currentUser = useCurrentUser( ) as RealmUser | null;
|
||||
|
||||
const [taxonQuery, setTaxonQuery] = useState( ( ) => (
|
||||
searchedTaxon
|
||||
? taxonDisplayName( searchedTaxon, currentUser )
|
||||
: ""
|
||||
) );
|
||||
|
||||
const { taxa, isLoading, isLocal } = useTaxonSearch( taxonQuery );
|
||||
|
||||
@@ -29,12 +38,21 @@ const SearchMyObservationsTaxon = ( ) => {
|
||||
|
||||
const onTaxonSelected = useCallback( ( newTaxon: ApiTaxon | null ) => {
|
||||
if ( newTaxon && typeof newTaxon.id === "number" && newTaxon.name ) {
|
||||
// useTaxonSearch can return either ApiTaxon-shaped or RealmTaxon-shaped
|
||||
// taxa depending on the source, so we have to check for both here.
|
||||
// TODO: normalize taxa at ingest.
|
||||
const realmTaxon = newTaxon as RealmTaxon;
|
||||
const iconUri = newTaxon.default_photo?.url
|
||||
|| realmTaxon.defaultPhoto?.url;
|
||||
const preferredCommonName = newTaxon.preferred_common_name
|
||||
|| realmTaxon.preferredCommonName;
|
||||
dispatch( {
|
||||
type: MY_OBSERVATIONS_ACTION.SET_TAXON_SEARCH,
|
||||
searchTaxon: {
|
||||
id: newTaxon.id,
|
||||
name: newTaxon.name,
|
||||
preferred_common_name: newTaxon.preferred_common_name,
|
||||
preferredCommonName,
|
||||
iconUri,
|
||||
},
|
||||
} );
|
||||
} else {
|
||||
@@ -43,7 +61,11 @@ const SearchMyObservationsTaxon = ( ) => {
|
||||
closeScreen( );
|
||||
}, [closeScreen, dispatch] );
|
||||
|
||||
const resetSearch = useCallback( ( ) => setTaxonQuery( "" ), [] );
|
||||
const resetSearch = useCallback( ( ) => {
|
||||
setTaxonQuery( "" );
|
||||
dispatch( { type: MY_OBSERVATIONS_ACTION.CLEAR_TAXON_SEARCH } );
|
||||
closeScreen( );
|
||||
}, [closeScreen, dispatch] );
|
||||
|
||||
const renderItem = useCallback(
|
||||
// no-unused-prop-types failing for components defined at runtime seems to
|
||||
@@ -68,6 +90,7 @@ const SearchMyObservationsTaxon = ( ) => {
|
||||
closeModal={closeScreen}
|
||||
headerText={t( "SEARCH" )}
|
||||
resetFilters={resetSearch}
|
||||
resetDisabled={!searchedTaxon}
|
||||
testID="SearchMyObservationsTaxon.close"
|
||||
/>
|
||||
<TaxonSearch
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import {
|
||||
Body3,
|
||||
INatIconButton,
|
||||
} from "components/SharedComponents";
|
||||
import { Image, View } from "components/styledComponents";
|
||||
import {
|
||||
MY_OBSERVATIONS_ACTION,
|
||||
useMyObservations,
|
||||
} from "providers/MyObservationsContext";
|
||||
import React from "react";
|
||||
import type { RealmUser } from "realmModels/types";
|
||||
import { taxonDisplayName } from "sharedHelpers/taxon";
|
||||
import { useCurrentUser, useTranslation } from "sharedHooks";
|
||||
|
||||
const SearchedTaxonBanner = ( ) => {
|
||||
const { t } = useTranslation( );
|
||||
const { state, dispatch } = useMyObservations( );
|
||||
const { searchedTaxon } = state;
|
||||
|
||||
// The Realm `User` class doesn't declare its schema fields as typed
|
||||
// instance properties (see realmModels/User.ts), so cast to the typed
|
||||
// RealmUser interface to access the user's name-display prefs.
|
||||
const currentUser = useCurrentUser( ) as RealmUser | null;
|
||||
|
||||
if ( !searchedTaxon ) return null;
|
||||
|
||||
const displayName = taxonDisplayName( searchedTaxon, currentUser );
|
||||
|
||||
return (
|
||||
<View
|
||||
className="flex-row items-center bg-white space-x-[20px]"
|
||||
testID="SearchedTaxonBanner"
|
||||
>
|
||||
<View className="flex-1 flex-row items-center space-x-[10px]">
|
||||
<View className="w-[44px] h-[44px] bg-lightGray">
|
||||
{searchedTaxon.iconUri && (
|
||||
<Image
|
||||
source={{ uri: searchedTaxon.iconUri }}
|
||||
className="w-full h-full"
|
||||
accessibilityIgnoresInvertColors
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<Body3 className="flex-1" numberOfLines={1}>
|
||||
{displayName}
|
||||
</Body3>
|
||||
</View>
|
||||
<INatIconButton
|
||||
icon="close"
|
||||
size={14}
|
||||
accessibilityLabel={t( "Close-search" )}
|
||||
onPress={( ) => dispatch( {
|
||||
type: MY_OBSERVATIONS_ACTION.CLEAR_TAXON_SEARCH,
|
||||
} )}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchedTaxonBanner;
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
INatIcon,
|
||||
} from "components/SharedComponents";
|
||||
import { View } from "components/styledComponents";
|
||||
import { useMyObservations } from "providers/MyObservationsContext";
|
||||
import React from "react";
|
||||
import { useCurrentUser, useTranslation } from "sharedHooks";
|
||||
import useStore from "stores/useStore";
|
||||
@@ -37,6 +38,13 @@ const SimpleHeader = ( {
|
||||
const setIsDefaultMode = useStore( state => state.layout.setIsDefaultMode );
|
||||
|
||||
const currentUser = useCurrentUser();
|
||||
const { state: myObsState } = useMyObservations( );
|
||||
const searchActive = myObsState.searchedTaxon !== null;
|
||||
|
||||
// While a search is active, the SearchedTaxonBanner is the only banner we
|
||||
// want to show. Suppress the announcement / advanced-mode / location-missing
|
||||
// banners so they don't compete for attention or change the layout.
|
||||
if ( searchActive ) return null;
|
||||
|
||||
const shouldShowAdvancedModeBanner = !!currentUser
|
||||
&& isDefaultMode
|
||||
|
||||
@@ -732,6 +732,10 @@ LOG-IN-TO-INATURALIST = LOG IN TO INATURALIST
|
||||
Log-in-to-iNaturalist = Log in to iNaturalist
|
||||
LOG-OUT = LOG OUT
|
||||
LOG-OUT--question = LOG OUT?
|
||||
# When the user searches their own observations for something they haven't observed
|
||||
Looks-like-you-havent-observed-this-yet-time-to-keep-exploring =
|
||||
Looks like you haven't observed this yet.
|
||||
Time to keep exploring!
|
||||
Lowest = Lowest
|
||||
LOWEST-RANK = LOWEST RANK
|
||||
MAP = MAP
|
||||
|
||||
@@ -422,6 +422,7 @@
|
||||
"Log-in-to-iNaturalist": "Log in to iNaturalist",
|
||||
"LOG-OUT": "LOG OUT",
|
||||
"LOG-OUT--question": "LOG OUT?",
|
||||
"Looks-like-you-havent-observed-this-yet-time-to-keep-exploring": "Looks like you haven't observed this yet.\nTime to keep exploring!",
|
||||
"Lowest": "Lowest",
|
||||
"LOWEST-RANK": "LOWEST RANK",
|
||||
"MAP": "MAP",
|
||||
|
||||
@@ -732,6 +732,10 @@ LOG-IN-TO-INATURALIST = LOG IN TO INATURALIST
|
||||
Log-in-to-iNaturalist = Log in to iNaturalist
|
||||
LOG-OUT = LOG OUT
|
||||
LOG-OUT--question = LOG OUT?
|
||||
# When the user searches their own observations for something they haven't observed
|
||||
Looks-like-you-havent-observed-this-yet-time-to-keep-exploring =
|
||||
Looks like you haven't observed this yet.
|
||||
Time to keep exploring!
|
||||
Lowest = Lowest
|
||||
LOWEST-RANK = LOWEST RANK
|
||||
MAP = MAP
|
||||
|
||||
@@ -12,7 +12,8 @@ export enum MY_OBSERVATIONS_ACTION {
|
||||
export interface MyObservationsTaxon {
|
||||
id: number;
|
||||
name: string;
|
||||
preferred_common_name?: string;
|
||||
preferredCommonName?: string;
|
||||
iconUri?: string;
|
||||
}
|
||||
|
||||
export interface MyObservationsState {
|
||||
|
||||
@@ -179,6 +179,25 @@ export function accessibleTaxonName(
|
||||
return t( "accessible-comname-sciname", { scientificName, commonName } );
|
||||
}
|
||||
|
||||
interface TaxonName {
|
||||
name: string;
|
||||
preferredCommonName?: string;
|
||||
}
|
||||
|
||||
// Returns a single taxon name to show for a taxon in a single-line context
|
||||
// like banners & search bars, honoring the user's name-display preferences.
|
||||
// For two-line rendering with italics, use <DisplayTaxonName /> instead.
|
||||
export function taxonDisplayName(
|
||||
taxon: TaxonName,
|
||||
user: User | null,
|
||||
): string {
|
||||
const preferScientific = user?.prefers_scientific_name_first === true
|
||||
|| user?.prefers_common_names === false;
|
||||
return preferScientific
|
||||
? taxon.name
|
||||
: ( taxon.preferredCommonName || taxon.name );
|
||||
}
|
||||
|
||||
// Translates rank in a way that can be statically checked
|
||||
export function translatedRank( rank: string, t: ( key: string ) => string ) {
|
||||
switch ( rank ) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useNetInfo } from "@react-native-community/netinfo";
|
||||
import { fetchSearchResults } from "api/search";
|
||||
import type { ApiOpts } from "api/types";
|
||||
import { RealmContext } from "providers/contexts";
|
||||
@@ -32,6 +33,7 @@ function saveTaxaToRealm( taxa: Taxon[], realm: Realm ) {
|
||||
const useTaxonSearch = ( taxonQueryArg = "" ) => {
|
||||
const realm = useRealm( );
|
||||
const iconicTaxa = useIconicTaxa( { reload: false } );
|
||||
const { isConnected } = useNetInfo( );
|
||||
// Remove leading and trailing whitespace, no need to perform new queries or
|
||||
// potentially get different results b/c of meaningless whitespace
|
||||
const taxonQuery = taxonQueryArg.trim();
|
||||
@@ -39,7 +41,9 @@ const useTaxonSearch = ( taxonQueryArg = "" ) => {
|
||||
|
||||
const shouldFetchRemote = taxonQuery.length > 0;
|
||||
|
||||
const { data: remoteTaxa, refetch, isLoading } = useAuthenticatedQuery(
|
||||
const {
|
||||
data: remoteTaxa, refetch, isLoading, isFetched,
|
||||
} = useAuthenticatedQuery(
|
||||
["fetchTaxonSuggestions", taxonQuery],
|
||||
async ( optsWithAuth: ApiOpts ) => {
|
||||
const apiTaxa = await fetchSearchResults(
|
||||
@@ -96,6 +100,14 @@ const useTaxonSearch = ( taxonQueryArg = "" ) => {
|
||||
|
||||
if ( isLoading ) return;
|
||||
|
||||
// Don't fall back to local results until the remote query has actually
|
||||
// run at least once. useAuthenticatedQuery starts with enabled=false
|
||||
// while it resolves the auth state, which makes isLoading=false even
|
||||
// though no remote fetch has happened yet — without this check we'd
|
||||
// flash the "Showing offline search results" callout in that window.
|
||||
// Skip the gate when we know we're offline and will need remote taxa
|
||||
if ( shouldFetchRemote && !isFetched && isConnected !== false ) return;
|
||||
|
||||
if ( remoteTaxa && remoteTaxa.length > 0 ) {
|
||||
if ( isSubscribed ) setLocalTaxa( null );
|
||||
return;
|
||||
@@ -116,10 +128,13 @@ const useTaxonSearch = ( taxonQueryArg = "" ) => {
|
||||
isSubscribed = false;
|
||||
};
|
||||
}, [
|
||||
isConnected,
|
||||
isFetched,
|
||||
isLoading,
|
||||
realm,
|
||||
remoteTaxa,
|
||||
safeRealmSearch,
|
||||
shouldFetchRemote,
|
||||
taxonQuery,
|
||||
] );
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { screen } from "@testing-library/react-native";
|
||||
import MyObservationsSimple, { OBSERVATIONS_TAB }
|
||||
from "components/MyObservations/MyObservationsSimple";
|
||||
import { MyObservationsProvider } from "providers/MyObservationsContext";
|
||||
import React from "react";
|
||||
// import DeviceInfo from "react-native-device-info";
|
||||
import useDeviceOrientation from "sharedHooks/useDeviceOrientation";
|
||||
@@ -59,14 +60,16 @@ jest.mock( "sharedHooks/useDeviceOrientation", ( ) => ( {
|
||||
} ) );
|
||||
|
||||
const renderMyObservations = layout => renderComponent(
|
||||
<MyObservationsSimple
|
||||
layout={layout}
|
||||
observations={mockObservations}
|
||||
onEndReached={jest.fn( )}
|
||||
toggleLayout={jest.fn( )}
|
||||
setShowLoginSheet={jest.fn( )}
|
||||
activeTab={OBSERVATIONS_TAB}
|
||||
/>,
|
||||
<MyObservationsProvider>
|
||||
<MyObservationsSimple
|
||||
layout={layout}
|
||||
observations={mockObservations}
|
||||
onEndReached={jest.fn( )}
|
||||
toggleLayout={jest.fn( )}
|
||||
setShowLoginSheet={jest.fn( )}
|
||||
activeTab={OBSERVATIONS_TAB}
|
||||
/>
|
||||
</MyObservationsProvider>,
|
||||
);
|
||||
|
||||
describe( "MyObservationsSimple", () => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useNetInfo } from "@react-native-community/netinfo";
|
||||
import { renderHook } from "@testing-library/react-native";
|
||||
import useAuthenticatedQuery from "sharedHooks/useAuthenticatedQuery";
|
||||
import useTaxonSearch from "sharedHooks/useTaxonSearch";
|
||||
@@ -18,6 +19,7 @@ jest.mock( "sharedHooks/useAuthenticatedQuery", ( ) => ( {
|
||||
data: [],
|
||||
refetch: jest.mock( ),
|
||||
isLoading: false,
|
||||
isFetched: true,
|
||||
} ) ),
|
||||
} ) );
|
||||
|
||||
@@ -74,6 +76,7 @@ describe( "useTaxonSearch", ( ) => {
|
||||
data: [factory( "LocalTaxon" )],
|
||||
refetch: jest.mock( ),
|
||||
isLoading: false,
|
||||
isFetched: true,
|
||||
} ) );
|
||||
}
|
||||
|
||||
@@ -88,4 +91,27 @@ describe( "useTaxonSearch", ( ) => {
|
||||
renderHook( ( ) => useTaxonSearch( "foo" ) );
|
||||
expect( mockRealmObjects ).not.toHaveBeenCalledWith( "Taxon" );
|
||||
} );
|
||||
|
||||
it( "when online should not request local taxa while remote query has not run yet", ( ) => {
|
||||
useAuthenticatedQuery.mockImplementation( ( ) => ( {
|
||||
data: undefined,
|
||||
refetch: jest.mock( ),
|
||||
isLoading: false,
|
||||
isFetched: false,
|
||||
} ) );
|
||||
renderHook( ( ) => useTaxonSearch( "foo" ) );
|
||||
expect( mockRealmObjects ).not.toHaveBeenCalledWith( "Taxon" );
|
||||
} );
|
||||
|
||||
it( "when offline should request local taxa offline even before the remote query runs", ( ) => {
|
||||
useNetInfo.mockReturnValueOnce( { isConnected: false } );
|
||||
useAuthenticatedQuery.mockImplementation( ( ) => ( {
|
||||
data: undefined,
|
||||
refetch: jest.mock( ),
|
||||
isLoading: false,
|
||||
isFetched: false,
|
||||
} ) );
|
||||
renderHook( ( ) => useTaxonSearch( "foo" ) );
|
||||
expect( mockRealmObjects ).toHaveBeenCalledWith( "Taxon" );
|
||||
} );
|
||||
} );
|
||||
Reference in new issue
Block a user