Explore nearby and map area (#1655)

* Bugfix: map area search was broken after Nearby filter set
* Made EXPLORE_ACTION.SET_MAP_BOUNDARIES remove lat, lng, and radius
  attributes so we don't end up applying both kinds of geographic filters at
  the same time
* Renamed setExploreLocation to defaultExploreLocation because it doesn't set
  anything
* Added a unit test fot the Explore reducer
* Bugfix: zoom Explore to nearby after granting permission
This commit is contained in:
Ken-ichi
2024-06-05 17:10:49 -07:00
committed by GitHub
parent 29ef611e03
commit 4f46cf5dfd
7 changed files with 104 additions and 58 deletions

View File

@@ -82,7 +82,7 @@ const FilterModal = ( {
discardChanges,
isNotInitialState,
numberOfFilters,
setExploreLocation
defaultExploreLocation
} = useExplore();
const {
taxon,
@@ -661,7 +661,7 @@ const FilterModal = ( {
<Body3
accessibilityRole="button"
onPress={async ( ) => {
const exploreLocation = await setExploreLocation( );
const exploreLocation = await defaultExploreLocation( );
dispatch( { type: EXPLORE_ACTION.RESET, exploreLocation } );
}}
>

View File

@@ -8,7 +8,11 @@ import {
useExplore
} from "providers/ExploreContext.tsx";
import type { Node } from "react";
import React, { useEffect, useState } from "react";
import React, {
useCallback,
useEffect,
useState
} from "react";
import { useCurrentUser, useIsConnected, useTranslation } from "sharedHooks";
import useStore from "stores/useStore";
@@ -27,7 +31,7 @@ const RootExploreContainerWithContext = ( ): Node => {
const worldwidePlaceText = t( "Worldwide" );
const {
state, dispatch, makeSnapshot, setExploreLocation
state, dispatch, makeSnapshot, defaultExploreLocation
} = useExplore( );
const [showFiltersModal, setShowFiltersModal] = useState( false );
@@ -95,30 +99,23 @@ const RootExploreContainerWithContext = ( ): Node => {
makeSnapshot( );
};
const onPermissionGranted = async ( ) => {
if ( state.place_guess ) { return; }
const exploreLocation = await setExploreLocation( );
const onPermissionGranted = useCallback( async ( ) => {
const exploreLocation = await defaultExploreLocation( );
dispatch( {
type: EXPLORE_ACTION.SET_EXPLORE_LOCATION,
exploreLocation
} );
};
}, [
defaultExploreLocation,
dispatch
] );
const onPermissionDenied = ( ) => {
if ( state.place_guess ) { return; }
const resetToWorldWide = useCallback( ( ) => {
dispatch( {
type: EXPLORE_ACTION.SET_PLACE,
placeGuess: t( "Worldwide" )
placeGuess: worldwidePlaceText
} );
};
const onPermissionBlocked = ( ) => {
if ( state.place_guess ) { return; }
dispatch( {
type: EXPLORE_ACTION.SET_PLACE,
placeGuess: t( "Worldwide" )
} );
};
}, [dispatch, worldwidePlaceText] );
useEffect( ( ) => {
navigation.addListener( "focus", ( ) => {
@@ -154,8 +151,8 @@ const RootExploreContainerWithContext = ( ): Node => {
<LocationPermissionGate
permissionNeeded
onPermissionGranted={onPermissionGranted}
onPermissionDenied={onPermissionDenied}
onPermissionBlocked={onPermissionBlocked}
onPermissionDenied={resetToWorldWide}
onPermissionBlocked={resetToWorldWide}
withoutNavigation
/>
</>

View File

@@ -37,7 +37,7 @@ type Props = {
const ExploreLocationSearch = ( { closeModal, updateLocation }: Props ): Node => {
const { t } = useTranslation( );
const { dispatch, setExploreLocation } = useExplore( );
const { dispatch, defaultExploreLocation } = useExplore( );
const [locationName, setLocationName] = useState( "" );
const [permissionNeeded, setPermissionNeeded] = useState( false );
@@ -146,7 +146,7 @@ const ExploreLocationSearch = ( { closeModal, updateLocation }: Props ): Node =>
withoutNavigation
onPermissionGranted={async ( ) => {
setPermissionNeeded( false );
const exploreLocation = await setExploreLocation( );
const exploreLocation = await defaultExploreLocation( );
dispatch( { type: EXPLORE_ACTION.SET_EXPLORE_LOCATION, exploreLocation } );
closeModal();
}}

View File

@@ -50,13 +50,11 @@ const useMapLocation = ( ): Object => {
};
setMapBoundaries( boundaryAPIParams );
logger.info( "setting map region based on user pan/zoom" );
setMapRegion( newRegion );
return boundaryAPIParams;
}, [t, setMapBoundaries, setMapRegion] );
const redoSearchInMapArea = ( ) => {
logger.info( "searching for observations with map boundaries: ", mapBoundaries );
setShowMapBoundaryButton( false );
dispatch( { type: EXPLORE_ACTION.SET_MAP_BOUNDARIES, mapBoundaries } );
};

View File

@@ -12,7 +12,7 @@ import useStore from "stores/useStore";
const useParams = ( ): Object => {
const { t } = useTranslation( );
const { params } = useRoute( );
const { dispatch, setExploreLocation } = useExplore( );
const { dispatch, defaultExploreLocation } = useExplore( );
const storedParams = useStore( state => state.storedParams );
const worldwidePlaceText = t( "Worldwide" );
@@ -32,7 +32,7 @@ const useParams = ( ): Object => {
setWorldwide( );
}
if ( params?.nearby ) {
const exploreLocation = await setExploreLocation( );
const exploreLocation = await defaultExploreLocation( );
dispatch( {
type: EXPLORE_ACTION.SET_EXPLORE_LOCATION,
exploreLocation
@@ -75,7 +75,7 @@ const useParams = ( ): Object => {
}, [
dispatch,
params,
setExploreLocation,
defaultExploreLocation,
worldwidePlaceText
] );

View File

@@ -6,34 +6,34 @@ import { LatLng } from "react-native-maps";
import fetchUserLocation from "sharedHelpers/fetchUserLocation";
export enum EXPLORE_ACTION {
CHANGE_SORT_BY = "CHANGE_SORT_BY",
CHANGE_TAXON = "CHANGE_TAXON",
DISCARD = "DISCARD",
RESET = "RESET",
CHANGE_TAXON = "CHANGE_TAXON",
SET_TAXON_NAME = "SET_TAXON_NAME",
SET_EXPLORE_LOCATION = "SET_EXPLORE_LOCATION",
SET_PLACE = "SET_PLACE",
SET_USER = "SET_USER",
SET_PROJECT = "SET_PROJECT",
CHANGE_SORT_BY = "CHANGE_SORT_BY",
TOGGLE_RESEARCH_GRADE = "TOGGLE_RESEARCH_GRADE",
TOGGLE_NEEDS_ID = "TOGGLE_NEEDS_ID",
TOGGLE_CASUAL = "TOGGLE_CASUAL",
SET_HIGHEST_TAXONOMIC_RANK = "SET_HIGHEST_TAXONOMIC_RANK",
SET_LOWEST_TAXONOMIC_RANK = "SET_LOWEST_TAXONOMIC_RANK",
SET_DATE_OBSERVED_MONTHS = "SET_DATE_OBSERVED_MONTHS",
SET_DATE_OBSERVED_EXACT = "SET_DATE_OBSERVED_EXACT",
SET_DATE_OBSERVED_RANGE = "SET_DATE_OBSERVED_RANGE",
SET_DATE_OBSERVED_ALL = "SET_DATE_OBSERVED_ALL",
SET_DATE_OBSERVED_EXACT = "SET_DATE_OBSERVED_EXACT",
SET_DATE_OBSERVED_MONTHS = "SET_DATE_OBSERVED_MONTHS",
SET_DATE_OBSERVED_RANGE = "SET_DATE_OBSERVED_RANGE",
SET_DATE_UPLOADED_ALL = "SET_DATE_UPLOADED_ALL",
SET_DATE_UPLOADED_EXACT = "SET_DATE_UPLOADED_EXACT",
SET_DATE_UPLOADED_RANGE = "SET_DATE_UPLOADED_RANGE",
SET_DATE_UPLOADED_ALL = "SET_DATE_UPLOADED_ALL",
SET_MEDIA = "SET_MEDIA",
SET_ESTABLISHMENT_MEAN = "SET_ESTABLISHMENT_MEAN",
SET_WILD_STATUS = "SET_WILD_STATUS",
SET_REVIEWED = "SET_REVIEWED",
SET_PHOTO_LICENSE = "SET_PHOTO_LICENSE",
SET_EXPLORE_LOCATION = "SET_EXPLORE_LOCATION",
SET_HIGHEST_TAXONOMIC_RANK = "SET_HIGHEST_TAXONOMIC_RANK",
SET_LOWEST_TAXONOMIC_RANK = "SET_LOWEST_TAXONOMIC_RANK",
SET_MAP_BOUNDARIES = "SET_MAP_BOUNDARIES",
USE_STORED_STATE = "USE_STORED_STATE",
SET_MEDIA = "SET_MEDIA",
SET_PHOTO_LICENSE = "SET_PHOTO_LICENSE",
SET_PLACE = "SET_PLACE",
SET_PROJECT = "SET_PROJECT",
SET_REVIEWED = "SET_REVIEWED",
SET_TAXON_NAME = "SET_TAXON_NAME",
SET_USER = "SET_USER",
SET_WILD_STATUS = "SET_WILD_STATUS",
TOGGLE_CASUAL = "TOGGLE_CASUAL",
TOGGLE_NEEDS_ID = "TOGGLE_NEEDS_ID",
TOGGLE_RESEARCH_GRADE = "TOGGLE_RESEARCH_GRADE",
USE_STORED_STATE = "USE_STORED_STATE"
}
export enum SORT_BY {
@@ -293,7 +293,7 @@ function isValidDateFormat( date: string ): boolean {
return regex.test( date );
}
async function setExploreLocation( ) {
async function defaultExploreLocation( ) {
const location = await fetchUserLocation( );
if ( !location || !location.latitude ) {
return {
@@ -496,14 +496,17 @@ function exploreReducer( state: State, action: Action ) {
...state,
reviewedFilter: action.reviewedFilter
};
case EXPLORE_ACTION.SET_MAP_BOUNDARIES:
// eslint-disable-next-line no-case-declarations
const boundState = {
case EXPLORE_ACTION.SET_MAP_BOUNDARIES: {
const newState = {
...state,
...action.mapBoundaries
};
delete boundState.place_id;
return boundState;
delete newState.place_id;
delete newState.lat;
delete newState.lng;
delete newState.radius;
return newState;
}
case EXPLORE_ACTION.USE_STORED_STATE:
return {
...action.storedState
@@ -559,7 +562,7 @@ const ExploreProvider = ( { children }: ExploreProviderProps ) => {
const value = {
state,
dispatch,
setExploreLocation,
defaultExploreLocation,
isNotInitialState,
numberOfFilters,
makeSnapshot,
@@ -579,4 +582,8 @@ function useExplore() {
return context;
}
export { ExploreProvider, useExplore };
export {
ExploreProvider,
exploreReducer,
useExplore
};

View File

@@ -0,0 +1,44 @@
import {
EXPLORE_ACTION,
exploreReducer
} from "providers/ExploreContext.tsx";
import factory from "tests/factory";
describe( "ExploreContext", ( ) => {
describe( "exploreReducer", ( ) => {
describe( EXPLORE_ACTION.SET_PLACE, ( ) => {
it( "should remove lat and lng when place set", ( ) => {
const initialState = { lat: 1, lng: 1 };
const reducedState = exploreReducer( initialState, {
type: EXPLORE_ACTION.SET_PLACE,
place: factory( "RemotePlace" )
} );
expect( initialState.lat ).not.toBeUndefined( );
expect( initialState.lng ).not.toBeUndefined( );
expect( reducedState.lat ).toBeUndefined( );
expect( reducedState.lng ).toBeUndefined( );
} );
} );
describe( EXPLORE_ACTION.SET_MAP_BOUNDARIES, ( ) => {
it( "should remove lat, lng, and radius", ( ) => {
const initialState = { lat: 1, lng: 1, radius: 50 };
const reducedState = exploreReducer( initialState, {
type: EXPLORE_ACTION.SET_MAP_BOUNDARIES,
mapBoundaries: {
swlat: 0,
swlng: 0,
nelat: 1,
nelng: 1,
place_guess: "somwhere"
}
} );
expect( initialState.lat ).not.toBeUndefined( );
expect( initialState.lng ).not.toBeUndefined( );
expect( initialState.radius ).not.toBeUndefined( );
expect( reducedState.lat ).toBeUndefined( );
expect( reducedState.lng ).toBeUndefined( );
expect( reducedState.radius ).toBeUndefined( );
} );
} );
} );
} );