mirror of
https://github.com/inaturalist/iNaturalistReactNative.git
synced 2026-05-04 21:53:59 -04:00
* split notifications into tabs * lots of TypeScript conversion * feat: resize Heading5 and add Heading6 (closes #2480) * fix: mark remote observations as viewed from ObsDetails * feat: show indicator in Notifications tabs if unviewed notifications Closes #2451
131 lines
3.8 KiB
TypeScript
131 lines
3.8 KiB
TypeScript
import { fetchObservationUpdates, fetchRemoteObservations } from "api/observations";
|
|
import type {
|
|
ApiNotification,
|
|
ApiObservation,
|
|
ApiObservationsUpdatesParams,
|
|
ApiOpts
|
|
} from "api/types";
|
|
import { flatten } from "lodash";
|
|
import { RealmContext } from "providers/contexts.ts";
|
|
import type Realm from "realm";
|
|
import Observation from "realmModels/Observation";
|
|
import { useAuthenticatedInfiniteQuery, useCurrentUser } from "sharedHooks";
|
|
|
|
const { useRealm } = RealmContext;
|
|
|
|
// Extends API response with data we need in this app
|
|
export interface Notification extends ApiNotification {
|
|
resource?: ApiObservation;
|
|
viewerOwnsResource?: boolean;
|
|
}
|
|
|
|
interface InfiniteNotificationsScrollResponse {
|
|
fetchNextPage: ( ) => void;
|
|
isError?: boolean;
|
|
isFetching?: boolean;
|
|
isInitialLoading?: boolean;
|
|
notifications: Notification[];
|
|
refetch: ( ) => void;
|
|
}
|
|
|
|
const BASE_PARAMS: ApiObservationsUpdatesParams = {
|
|
// observations_by: "owner",
|
|
fields: "all", // TODO narrow this down. this has a massive response
|
|
per_page: 30,
|
|
ttl: -1,
|
|
page: 1
|
|
};
|
|
|
|
async function fetchObsByUUIDs(
|
|
uuids: string[],
|
|
authOptions: ApiOpts,
|
|
realm: Realm,
|
|
options: {
|
|
save?: boolean
|
|
} = {}
|
|
) {
|
|
// TODO convert api/observations to TS
|
|
const observations: ApiObservation[] | null = await fetchRemoteObservations(
|
|
uuids,
|
|
{ fields: Observation.FIELDS },
|
|
authOptions
|
|
);
|
|
if ( options.save ) {
|
|
Observation.upsertRemoteObservations( observations, realm );
|
|
}
|
|
return observations;
|
|
}
|
|
|
|
const useInfiniteNotificationsScroll = (
|
|
notificationParams: ApiObservationsUpdatesParams = {}
|
|
): InfiniteNotificationsScrollResponse => {
|
|
const currentUser = useCurrentUser( );
|
|
const realm = useRealm( );
|
|
|
|
const queryKey = ["useInfiniteNotificationsScroll", JSON.stringify( notificationParams )];
|
|
|
|
const infQueryResult = useAuthenticatedInfiniteQuery(
|
|
queryKey,
|
|
async ( { pageParam }: { pageParam: number }, optsWithAuth: ApiOpts ) => {
|
|
const params = { ...BASE_PARAMS, ...notificationParams };
|
|
|
|
if ( pageParam ) {
|
|
params.page = pageParam;
|
|
} else {
|
|
params.page = 1;
|
|
}
|
|
|
|
const response: null | ApiNotification[] = await fetchObservationUpdates(
|
|
params,
|
|
optsWithAuth
|
|
);
|
|
|
|
// Sometimes updates linger after notifiers that generated them have been deleted
|
|
const updatesWithContent = response?.filter(
|
|
update => update.comment || update.identification
|
|
) || [];
|
|
const obsUUIDs = updatesWithContent.map( obsUpdate => obsUpdate.resource_uuid );
|
|
if ( obsUUIDs.length > 0 ) {
|
|
const observations = await fetchObsByUUIDs(
|
|
obsUUIDs,
|
|
optsWithAuth,
|
|
realm,
|
|
{ save: params.observations_by === "owner" }
|
|
);
|
|
if ( observations ) {
|
|
return updatesWithContent.map( ( update: Notification ) => {
|
|
const resource = observations.find(
|
|
( o: ApiObservation ) => o.uuid === update.resource_uuid
|
|
);
|
|
update.resource = resource;
|
|
update.viewerOwnsResource = resource?.user?.id === currentUser?.id;
|
|
return update;
|
|
} );
|
|
}
|
|
}
|
|
|
|
return updatesWithContent;
|
|
},
|
|
{
|
|
getNextPageParam: ( lastPage, allPages ) => ( lastPage.length > 0
|
|
? allPages.length + 1
|
|
: undefined ),
|
|
enabled: !!( currentUser )
|
|
}
|
|
);
|
|
|
|
return {
|
|
refetch: infQueryResult.refetch,
|
|
isError: infQueryResult.isError,
|
|
isFetching: infQueryResult.isFetching,
|
|
isInitialLoading: infQueryResult.isInitialLoading,
|
|
// Disable fetchNextPage if signed out
|
|
fetchNextPage: currentUser
|
|
? infQueryResult.fetchNextPage
|
|
: ( ) => undefined,
|
|
notifications: flatten( infQueryResult?.data?.pages )
|
|
};
|
|
};
|
|
|
|
export default useInfiniteNotificationsScroll;
|