From c034dc7abba173ded21bd91d83c2c6e482f9f8a6 Mon Sep 17 00:00:00 2001 From: James Grugett Date: Sun, 28 Aug 2022 15:08:10 -0500 Subject: [PATCH] Use single react query to subscribe to notifications --- web/components/groups/group-chat.tsx | 13 ++-- web/hooks/use-notifications.ts | 88 +++++++++------------------- web/lib/firebase/notifications.ts | 16 ----- web/pages/notifications.tsx | 33 +++-------- 4 files changed, 43 insertions(+), 107 deletions(-) diff --git a/web/components/groups/group-chat.tsx b/web/components/groups/group-chat.tsx index 781705c2..0cec8885 100644 --- a/web/components/groups/group-chat.tsx +++ b/web/components/groups/group-chat.tsx @@ -278,12 +278,16 @@ function GroupChatNotificationsIcon(props: { }) { const { privateUser, group, shouldSetAsSeen, hidden } = props const preferredNotificationsForThisGroup = useUnseenPreferredNotifications( - privateUser, - { - customHref: `/group/${group.slug}`, - } + privateUser + // Disabled tracking by customHref for now. + // { + // customHref: `/group/${group.slug}`, + // } ) + useEffect(() => { + if (!preferredNotificationsForThisGroup) return + preferredNotificationsForThisGroup.forEach((notification) => { if ( (shouldSetAsSeen && notification.isSeenOnHref?.includes('chat')) || @@ -299,6 +303,7 @@ function GroupChatNotificationsIcon(props: {
0 && !shouldSetAsSeen ? 'absolute right-4 top-4 h-3 w-3 rounded-full border-2 border-white bg-red-500' diff --git a/web/hooks/use-notifications.ts b/web/hooks/use-notifications.ts index 32500943..f106c502 100644 --- a/web/hooks/use-notifications.ts +++ b/web/hooks/use-notifications.ts @@ -1,13 +1,9 @@ -import { useEffect, useMemo, useState } from 'react' +import { useMemo } from 'react' import { notification_subscribe_types, PrivateUser } from 'common/user' import { Notification } from 'common/notification' -import { - getNotificationsQuery, - listenForNotifications, -} from 'web/lib/firebase/notifications' +import { getNotificationsQuery } from 'web/lib/firebase/notifications' import { groupBy, map, partition } from 'lodash' import { useFirestoreQueryData } from '@react-query-firebase/firestore' -import { NOTIFICATIONS_PER_PAGE } from 'web/pages/notifications' export type NotificationGroup = { notifications: Notification[] @@ -17,49 +13,49 @@ export type NotificationGroup = { type: 'income' | 'normal' } -// For some reason react-query subscriptions don't actually listen for notifications -// Use useUnseenPreferredNotificationGroups to listen for new notifications -export function usePreferredGroupedNotifications( - privateUser: PrivateUser, - cachedNotifications?: Notification[] -) { +function usePreferredNotifications(privateUser: PrivateUser) { const result = useFirestoreQueryData( ['notifications-all', privateUser.id], - getNotificationsQuery(privateUser.id) + getNotificationsQuery(privateUser.id), + { subscribe: true, includeMetadataChanges: true }, + // Temporary workaround for react-query bug: + // https://github.com/invertase/react-query-firebase/issues/25 + { cacheTime: 0 } ) const notifications = useMemo(() => { - if (result.isLoading) return cachedNotifications ?? [] - if (!result.data) return cachedNotifications ?? [] + if (!result.data) return undefined const notifications = result.data as Notification[] return getAppropriateNotifications( notifications, privateUser.notificationPreferences ).filter((n) => !n.isSeenOnHref) - }, [ - cachedNotifications, - privateUser.notificationPreferences, - result.data, - result.isLoading, - ]) + }, [privateUser.notificationPreferences, result.data]) + return notifications +} + +export function useUnseenPreferredNotifications(privateUser: PrivateUser) { + const notifications = usePreferredNotifications(privateUser) + const unseen = useMemo( + () => notifications && notifications.filter((n) => !n.isSeen), + [notifications] + ) + return unseen +} + +export function usePreferredGroupedNotifications(privateUser: PrivateUser) { + const notifications = usePreferredNotifications(privateUser) return useMemo(() => { if (notifications) return groupNotifications(notifications) }, [notifications]) } export function useUnseenPreferredNotificationGroups(privateUser: PrivateUser) { - const notifications = useUnseenPreferredNotifications(privateUser, {}) - const [notificationGroups, setNotificationGroups] = useState< - NotificationGroup[] | undefined - >(undefined) - useEffect(() => { - if (!notifications) return - - const groupedNotifications = groupNotifications(notifications) - setNotificationGroups(groupedNotifications) + const notifications = useUnseenPreferredNotifications(privateUser) + return useMemo(() => { + if (notifications) return groupNotifications(notifications) }, [notifications]) - return notificationGroups } export function groupNotifications(notifications: Notification[]) { @@ -114,36 +110,6 @@ export function groupNotifications(notifications: Notification[]) { return notificationGroups } -export function useUnseenPreferredNotifications( - privateUser: PrivateUser, - options: { customHref?: string }, - limit: number = NOTIFICATIONS_PER_PAGE -) { - const { customHref } = options - const [notifications, setNotifications] = useState([]) - const [userAppropriateNotifications, setUserAppropriateNotifications] = - useState([]) - - useEffect(() => { - return listenForNotifications(privateUser.id, setNotifications, { - unseenOnly: true, - limit, - }) - }, [limit, privateUser.id]) - - useEffect(() => { - const notificationsToShow = getAppropriateNotifications( - notifications, - privateUser.notificationPreferences - ).filter((n) => - customHref ? n.isSeenOnHref?.includes(customHref) : !n.isSeenOnHref - ) - setUserAppropriateNotifications(notificationsToShow) - }, [notifications, customHref, privateUser.notificationPreferences]) - - return userAppropriateNotifications -} - const lessPriorityReasons = [ 'on_contract_with_users_comment', 'on_contract_with_users_answer', diff --git a/web/lib/firebase/notifications.ts b/web/lib/firebase/notifications.ts index d2db3665..38d93402 100644 --- a/web/lib/firebase/notifications.ts +++ b/web/lib/firebase/notifications.ts @@ -1,7 +1,5 @@ import { collection, limit, orderBy, query, where } from 'firebase/firestore' -import { Notification } from 'common/notification' import { db } from 'web/lib/firebase/init' -import { listenForValues } from 'web/lib/firebase/utils' import { NOTIFICATIONS_PER_PAGE } from 'web/pages/notifications' export function getNotificationsQuery( @@ -23,17 +21,3 @@ export function getNotificationsQuery( limit(NOTIFICATIONS_PER_PAGE * 10) ) } - -export function listenForNotifications( - userId: string, - setNotifications: (notifs: Notification[]) => void, - unseenOnlyOptions?: { unseenOnly: boolean; limit: number } -) { - return listenForValues( - getNotificationsQuery(userId, unseenOnlyOptions), - (notifs) => { - notifs.sort((n1, n2) => n2.createdTime - n1.createdTime) - setNotifications(notifs) - } - ) -} diff --git a/web/pages/notifications.tsx b/web/pages/notifications.tsx index bfd18f7f..ef333383 100644 --- a/web/pages/notifications.tsx +++ b/web/pages/notifications.tsx @@ -45,6 +45,7 @@ import { SiteLink } from 'web/components/site-link' import { NotificationSettings } from 'web/components/NotificationSettings' import { SEO } from 'web/components/SEO' import { useUser } from 'web/hooks/use-user' +import { LoadingIndicator } from 'web/components/loading-indicator' export const NOTIFICATIONS_PER_PAGE = 30 const MULTIPLE_USERS_KEY = 'multipleUsers' @@ -58,16 +59,6 @@ export default function Notifications(props: { auth: { privateUser: PrivateUser } }) { const { privateUser } = props.auth - const local = safeLocalStorage() - let localNotifications = [] as Notification[] - const localSavedNotificationGroups = local?.getItem('notification-groups') - let localNotificationGroups = [] as NotificationGroup[] - if (localSavedNotificationGroups) { - localNotificationGroups = JSON.parse(localSavedNotificationGroups) - localNotifications = localNotificationGroups - .map((g) => g.notifications) - .flat() - } return ( @@ -84,12 +75,7 @@ export default function Notifications(props: { tabs={[ { title: 'Notifications', - content: ( - - ), + content: , }, { title: 'Settings', @@ -135,16 +121,10 @@ function RenderNotificationGroups(props: { ) } -function NotificationsList(props: { - privateUser: PrivateUser - cachedNotifications: Notification[] -}) { - const { privateUser, cachedNotifications } = props +function NotificationsList(props: { privateUser: PrivateUser }) { + const { privateUser } = props const [page, setPage] = useState(0) - const allGroupedNotifications = usePreferredGroupedNotifications( - privateUser, - cachedNotifications - ) + const allGroupedNotifications = usePreferredGroupedNotifications(privateUser) const paginatedGroupedNotifications = useMemo(() => { if (!allGroupedNotifications) return const start = page * NOTIFICATIONS_PER_PAGE @@ -163,7 +143,8 @@ function NotificationsList(props: { return maxNotificationsToShow }, [allGroupedNotifications, page]) - if (!paginatedGroupedNotifications || !allGroupedNotifications) return
+ if (!paginatedGroupedNotifications || !allGroupedNotifications) + return return (