mirror of
https://github.com/inaturalist/iNaturalistReactNative.git
synced 2026-08-02 10:27:34 -04:00
handle local sort for logged out users
This commit is contained in:
@@ -98,7 +98,7 @@ const MyObservationsResults = ( ) => {
|
||||
const localObservationIds = useLocalObservationIds();
|
||||
const sortMyObservationsEnabled = useFeatureFlag( FeatureFlag.SortMyObservationsEnabled );
|
||||
const {
|
||||
observationIds: serverOrderedObservationIds,
|
||||
observationIds: queryObservationIds,
|
||||
isServerAuthoritative,
|
||||
isFetchingNextPage: isFetchingNextPageFromQuery,
|
||||
fetchNextPage: fetchNextPageFromQuery,
|
||||
@@ -106,8 +106,8 @@ const MyObservationsResults = ( ) => {
|
||||
} = useMyObservationsQuery( );
|
||||
// Only use server-ordered list when the flag is on and the selected sort requires it
|
||||
const useServerOrder = sortMyObservationsEnabled && isServerAuthoritative;
|
||||
const observationIds = useServerOrder
|
||||
? serverOrderedObservationIds
|
||||
const observationIds = sortMyObservationsEnabled
|
||||
? queryObservationIds
|
||||
: localObservationIds;
|
||||
const {
|
||||
numUnuploadedObservations,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { RealmContext } from "providers/contexts";
|
||||
import { useMyObservations } from "providers/MyObservationsContext";
|
||||
import { useMemo } from "react";
|
||||
import { OBSERVATIONS_SORT } from "sharedHelpers/observationsSort";
|
||||
import { useCurrentUser } from "sharedHooks";
|
||||
import useLocalObservationIds from "sharedHooks/useLocalObservationIds";
|
||||
|
||||
import useServerOrderedObservations from "./useServerOrderedObservations";
|
||||
@@ -25,12 +26,22 @@ interface UseMyObservationsQueryResult {
|
||||
// and interact with their obs offline. This hook uses selected sort to determine whether Realm or
|
||||
// the server should be the authoritative source of a user's observations (unsynced obs
|
||||
// are always merged in at the top regardless of source).
|
||||
//
|
||||
// Logged-out users can never have server-ordered observations, since they can't upload until
|
||||
// they log in, so a non-default sort is applied to their local observations instead.
|
||||
|
||||
const useMyObservationsQuery = ( ): UseMyObservationsQueryResult => {
|
||||
const { state } = useMyObservations( );
|
||||
const currentUser = useCurrentUser( );
|
||||
const isDefaultSort = state.observationsSort === OBSERVATIONS_SORT.DATE_UPLOADED_NEWEST;
|
||||
const sortLocally = !isDefaultSort && !currentUser;
|
||||
const isServerAuthoritative = !isDefaultSort && !!currentUser;
|
||||
|
||||
const localObservationIds = useLocalObservationIds( );
|
||||
const localObservationIds = useLocalObservationIds(
|
||||
sortLocally
|
||||
? state.observationsSort
|
||||
: undefined,
|
||||
);
|
||||
|
||||
const {
|
||||
observationIds: serverObservationIds,
|
||||
@@ -41,7 +52,7 @@ const useMyObservationsQuery = ( ): UseMyObservationsQueryResult => {
|
||||
refetch,
|
||||
} = useServerOrderedObservations( {
|
||||
sortBy: state.observationsSort,
|
||||
enabled: !isDefaultSort,
|
||||
enabled: isServerAuthoritative,
|
||||
} );
|
||||
|
||||
// if we want obs from the server, we'll want to prepend local, unsynced obs to the top
|
||||
@@ -66,34 +77,40 @@ const useMyObservationsQuery = ( ): UseMyObservationsQueryResult => {
|
||||
|
||||
// dedupe in case any locally unsynced obs also exist in the server results
|
||||
const observationIds = useMemo( ( ) => {
|
||||
if ( isDefaultSort ) return localObservationIds;
|
||||
if ( isDefaultSort || sortLocally ) return localObservationIds;
|
||||
const unsyncedUuids = new Set( unsyncedObservationIds.map( o => o.uuid ) );
|
||||
return [
|
||||
...unsyncedObservationIds,
|
||||
...serverObservationIds.filter( o => !unsyncedUuids.has( o.uuid ) ),
|
||||
];
|
||||
}, [isDefaultSort, localObservationIds, unsyncedObservationIds, serverObservationIds] );
|
||||
}, [
|
||||
isDefaultSort,
|
||||
sortLocally,
|
||||
localObservationIds,
|
||||
unsyncedObservationIds,
|
||||
serverObservationIds,
|
||||
] );
|
||||
|
||||
return {
|
||||
observationIds,
|
||||
isServerAuthoritative: !isDefaultSort,
|
||||
isLoading: isDefaultSort
|
||||
? false
|
||||
: isLoading,
|
||||
isFetchingNextPage: isDefaultSort
|
||||
? false
|
||||
: isFetchingNextPage,
|
||||
error: isDefaultSort
|
||||
? null
|
||||
: error,
|
||||
// since we never fetched for default sort, we don't need to refetch or paginate.
|
||||
// pagination is still handled by useInfiniteObservationsScroll
|
||||
refetch: isDefaultSort
|
||||
? NOOP_REFETCH
|
||||
: refetch,
|
||||
fetchNextPage: isDefaultSort
|
||||
? NOOP_FETCH_NEXT_PAGE
|
||||
: fetchNextPage,
|
||||
isServerAuthoritative,
|
||||
isLoading: isServerAuthoritative
|
||||
? isLoading
|
||||
: false,
|
||||
isFetchingNextPage: isServerAuthoritative
|
||||
? isFetchingNextPage
|
||||
: false,
|
||||
error: isServerAuthoritative
|
||||
? error
|
||||
: null,
|
||||
// pagination only applies to the server-authoritative case; the default sort is handled by
|
||||
// useInfiniteObservationsScroll, and locally-sorted data for logged-out users loads from Realm
|
||||
refetch: isServerAuthoritative
|
||||
? refetch
|
||||
: NOOP_REFETCH,
|
||||
fetchNextPage: isServerAuthoritative
|
||||
? fetchNextPage
|
||||
: NOOP_FETCH_NEXT_PAGE,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -36,6 +36,25 @@ export function observationSortToApiParams( sort: OBSERVATIONS_SORT ): Observati
|
||||
return OBSERVATIONS_SORT_TO_API_PARAMS[sort];
|
||||
}
|
||||
|
||||
// [property, reverse] tuple, matching Realm's .sorted() argument shape
|
||||
type ObservationRealmSort = [string, boolean];
|
||||
|
||||
const OBSERVATIONS_SORT_TO_REALM_SORT: Record<OBSERVATIONS_SORT, ObservationRealmSort> = {
|
||||
[OBSERVATIONS_SORT.DATE_UPLOADED_NEWEST]: ["_created_at", true],
|
||||
[OBSERVATIONS_SORT.DATE_UPLOADED_OLDEST]: ["_created_at", false],
|
||||
// observed_on (a real date) is only populated once an observation has been uploaded and the
|
||||
// server computes it -- local-only observations only ever have the
|
||||
// observed_on_string set, so local sorting needs to use that field instead
|
||||
[OBSERVATIONS_SORT.DATE_OBSERVED_NEWEST]: ["observed_on_string", true],
|
||||
[OBSERVATIONS_SORT.DATE_OBSERVED_OLDEST]: ["observed_on_string", false],
|
||||
};
|
||||
|
||||
// For sorting local, unsynced observations directly in a Realm query -- used for logged-out
|
||||
// users, who can never have server-ordered observations
|
||||
export function observationSortToRealmSort( sort: OBSERVATIONS_SORT ): ObservationRealmSort {
|
||||
return OBSERVATIONS_SORT_TO_REALM_SORT[sort];
|
||||
}
|
||||
|
||||
export function useObservationsSortLabels( ): Record<OBSERVATIONS_SORT, ObservationSortLabels> {
|
||||
const { t } = useTranslation( );
|
||||
return {
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
import { RealmContext } from "providers/contexts";
|
||||
import { useMemo } from "react";
|
||||
import Observation from "realmModels/Observation";
|
||||
import type { OBSERVATIONS_SORT } from "sharedHelpers/observationsSort";
|
||||
import { observationSortToRealmSort } from "sharedHelpers/observationsSort";
|
||||
|
||||
const { useQuery } = RealmContext;
|
||||
|
||||
const useLocalObservationIds = ( ) => {
|
||||
const useLocalObservationIds = ( sortBy?: OBSERVATIONS_SORT ) => {
|
||||
const unsyncedObs = useQuery(
|
||||
{
|
||||
type: Observation,
|
||||
query: observations => observations
|
||||
.filtered( "_deleted_at == nil OR _pending_deletion == false OR _pending_deletion == nil" )
|
||||
.sorted( [["needs_sync", true], ["_created_at", true]] ),
|
||||
keyPaths: ["uuid"],
|
||||
.sorted( sortBy
|
||||
? [observationSortToRealmSort( sortBy )]
|
||||
: [["needs_sync", true], ["_created_at", true]] ),
|
||||
// widening this beyond uuid means more frequent re-renders for every consumer,
|
||||
// so we only do it when we need a local sort applied to the results
|
||||
keyPaths: sortBy
|
||||
? ["uuid", "_created_at", "observed_on_string"]
|
||||
: ["uuid"],
|
||||
},
|
||||
[],
|
||||
[sortBy],
|
||||
);
|
||||
|
||||
return useMemo(
|
||||
|
||||
Reference in New Issue
Block a user