UNPKG

@amityco/ts-sdk-react-native

Version:

Amity Social Cloud Typescript SDK

157 lines (128 loc) 4.47 kB
import { ASCApiError, ASCError } from '~/core/errors'; import { getUserMarker } from '~/marker/api'; import { onUserMarkerFetched } from '~/marker/events'; import { getActiveClient, getActiveUser } from '../api'; import { createQuery, runQuery } from '~/core/query'; import { UNSYNCED_OBJECT_CACHED_AT_MESSAGE, UNSYNCED_OBJECT_CACHED_AT_VALUE, } from '~/utils/constants'; import { isEqual } from '~/utils/isEqual'; import { convertGetterPropsToStatic } from '~/utils/object'; /** * * ```js * import { getUserUnread } from '@amityco/ts-sdk-react-native; * * const unsubscribe = getUserUnread(response => { * userUnread = response.data; * }); * ``` * * Observe current user's unread including unreadCount and hasMentioned from {@link Amity.UserMarker} * * @param callback the function to call when new data are available * @returns An {@link Amity.Unsubscriber} function to run when willing to stop observing the events * * @category Message Live Object */ export const getUserUnread = ( callback: Amity.LiveObjectCallback<Amity.UserUnread | undefined>, ): Amity.Unsubscriber => { const { _id: userId } = getActiveUser(); if (!userId) throw new ASCError( 'The _id has not been defined in ActiveUser', Amity.ClientError.UNKNOWN_ERROR, Amity.ErrorLevel.ERROR, ); const { log, cache } = getActiveClient(); if (!cache) { console.log('For using Live Object feature you need to enable Cache!'); } const timestamp = Date.now(); log(`liveUserUnread(tmpid: ${timestamp}) > listen`); const disposers: Amity.Unsubscriber[] = []; let isUnsyncedModel = false; // for messages let model: Omit<Amity.UserUnread, 'hasMentioned'> | undefined; const dispatcher = (data: Amity.LiveObject<Amity.UserMarker | undefined>) => { const { data: userUnread } = data; const callbackModel = userUnread ? { unreadCount: userUnread.unreadCount, isMentioned: userUnread.isMentioned, } : undefined; model = callbackModel ? convertGetterPropsToStatic(callbackModel) : callbackModel; callback({ data: callbackModel ? { ...callbackModel, isMentioned: callbackModel.isMentioned } : callbackModel, loading: data.loading, error: data.error, }); }; const realtimeRouter = (userMarkers: Amity.UserMarker[]) => { const filterUserMarkers = userMarkers.filter(userMarker => userId === userMarker.userId); const latestUserMarker = filterUserMarkers.reduce((currentMaxUserMarker, userMarker) => { if ( currentMaxUserMarker == null || new Date(userMarker.lastSyncAt).getTime() > new Date(currentMaxUserMarker.lastSyncAt).getTime() ) { return userMarker; } return currentMaxUserMarker; }, null as Amity.UserMarker | null); const eventModel = { unreadCount: latestUserMarker?.unreadCount ?? 0, isMentioned: filterUserMarkers.some(userMarker => !!userMarker.isMentioned), } as Amity.UserMarker; if (isEqual(model, eventModel)) return; dispatcher({ loading: false, data: eventModel, }); }; function isAmityUserMarkerData(data: unknown): data is Amity.UserMarker { /** * The `data` return from runQuery is Amity.UserMarker | undefined. * It's not located inside data field */ if (data == null) return false; return (data as { data: Amity.UserMarker }) != null; } const onFetch = () => { const query = createQuery(getUserMarker); runQuery(query, ({ error, data, loading, origin, cachedAt }) => { if (!isAmityUserMarkerData(data)) { dispatcher({ loading, data: undefined, origin, error }); return; } if (cachedAt === UNSYNCED_OBJECT_CACHED_AT_VALUE) { dispatcher({ data, origin, loading: false, error: new ASCApiError( UNSYNCED_OBJECT_CACHED_AT_MESSAGE, Amity.ClientError.DISALOOW_UNSYNCED_OBJECT, Amity.ErrorLevel.ERROR, ), }); isUnsyncedModel = true; disposers.forEach(fn => fn()); } else if (!isUnsyncedModel) { dispatcher({ loading, data, origin, error }); } if (error) { disposers.forEach(fn => fn()); } }); }; disposers.push(onUserMarkerFetched(userMarkers => realtimeRouter(userMarkers))); onFetch(); return () => { disposers.forEach(fn => fn()); }; };