Use react-query to cache notifications
This commit is contained in:
parent
7f8617832f
commit
8521b3a222
|
@ -12,7 +12,7 @@ import {
|
|||
import clsx from 'clsx'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useUser } from 'web/hooks/use-user'
|
||||
import { usePrivateUser, useUser } from 'web/hooks/use-user'
|
||||
import { firebaseLogout, User } from 'web/lib/firebase/users'
|
||||
import { ManifoldLogo } from './manifold-logo'
|
||||
import { MenuButton } from './menu'
|
||||
|
@ -26,8 +26,9 @@ import { groupPath } from 'web/lib/firebase/groups'
|
|||
import { trackCallback, withTracking } from 'web/lib/service/analytics'
|
||||
import { Group } from 'common/group'
|
||||
import { Spacer } from '../layout/spacer'
|
||||
import { usePreferredNotifications } from 'web/hooks/use-notifications'
|
||||
import { useUnseenPreferredNotifications } from 'web/hooks/use-notifications'
|
||||
import { setNotificationsAsSeen } from 'web/pages/notifications'
|
||||
import { PrivateUser } from 'common/lib/user'
|
||||
|
||||
function getNavigation() {
|
||||
return [
|
||||
|
@ -186,6 +187,7 @@ export default function Sidebar(props: { className?: string }) {
|
|||
const currentPage = router.pathname
|
||||
|
||||
const user = useUser()
|
||||
const privateUser = usePrivateUser(user?.id)
|
||||
const navigationOptions = !user ? signedOutNavigation : getNavigation()
|
||||
const mobileNavigationOptions = !user
|
||||
? signedOutMobileNavigation
|
||||
|
@ -220,11 +222,13 @@ export default function Sidebar(props: { className?: string }) {
|
|||
/>
|
||||
)}
|
||||
|
||||
<GroupsList
|
||||
currentPage={router.asPath}
|
||||
memberItems={memberItems}
|
||||
user={user}
|
||||
/>
|
||||
{privateUser && (
|
||||
<GroupsList
|
||||
currentPage={router.asPath}
|
||||
memberItems={memberItems}
|
||||
privateUser={privateUser}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Desktop navigation */}
|
||||
|
@ -243,11 +247,13 @@ export default function Sidebar(props: { className?: string }) {
|
|||
<div className="h-[1px] bg-gray-300" />
|
||||
</div>
|
||||
)}
|
||||
<GroupsList
|
||||
currentPage={router.asPath}
|
||||
memberItems={memberItems}
|
||||
user={user}
|
||||
/>
|
||||
{privateUser && (
|
||||
<GroupsList
|
||||
currentPage={router.asPath}
|
||||
memberItems={memberItems}
|
||||
privateUser={privateUser}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
|
@ -256,11 +262,10 @@ export default function Sidebar(props: { className?: string }) {
|
|||
function GroupsList(props: {
|
||||
currentPage: string
|
||||
memberItems: Item[]
|
||||
user: User | null | undefined
|
||||
privateUser: PrivateUser
|
||||
}) {
|
||||
const { currentPage, memberItems, user } = props
|
||||
const preferredNotifications = usePreferredNotifications(user?.id, {
|
||||
unseenOnly: true,
|
||||
const { currentPage, memberItems, privateUser } = props
|
||||
const preferredNotifications = useUnseenPreferredNotifications(privateUser, {
|
||||
customHref: '/group/',
|
||||
})
|
||||
|
||||
|
|
|
@ -4,45 +4,57 @@ import { Row } from 'web/components/layout/row'
|
|||
import { useEffect, useState } from 'react'
|
||||
import { usePrivateUser, useUser } from 'web/hooks/use-user'
|
||||
import { useRouter } from 'next/router'
|
||||
import { usePreferredGroupedNotifications } from 'web/hooks/use-notifications'
|
||||
import { useUnseenPreferredNotificationGroups } from 'web/hooks/use-notifications'
|
||||
import { NOTIFICATIONS_PER_PAGE } from 'web/pages/notifications'
|
||||
import { requestBonuses } from 'web/lib/firebase/api-call'
|
||||
import { PrivateUser } from 'common/lib/user'
|
||||
|
||||
export default function NotificationsIcon(props: { className?: string }) {
|
||||
const user = useUser()
|
||||
const privateUser = usePrivateUser(user?.id)
|
||||
const notifications = usePreferredGroupedNotifications(privateUser?.id, {
|
||||
unseenOnly: true,
|
||||
})
|
||||
const [seen, setSeen] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (!privateUser) return
|
||||
|
||||
if (Date.now() - (privateUser.lastTimeCheckedBonuses ?? 0) > 65 * 1000)
|
||||
requestBonuses({}).catch((error) => {
|
||||
console.log("couldn't get bonuses:", error.message)
|
||||
})
|
||||
}, [privateUser])
|
||||
|
||||
const router = useRouter()
|
||||
useEffect(() => {
|
||||
if (router.pathname.endsWith('notifications')) return setSeen(true)
|
||||
else setSeen(false)
|
||||
}, [router.pathname])
|
||||
if (user) {
|
||||
const bonusChecker = setTimeout(() => {
|
||||
requestBonuses({}).catch((error) => {
|
||||
console.log("couldn't get bonuses:", error.message)
|
||||
})
|
||||
return () => {
|
||||
clearInterval(bonusChecker)
|
||||
}
|
||||
}, 1000 * 120)
|
||||
}
|
||||
}, [user])
|
||||
|
||||
return (
|
||||
<Row className={clsx('justify-center')}>
|
||||
<div className={'relative'}>
|
||||
{!seen && notifications && notifications.length > 0 && (
|
||||
<div className="-mt-0.75 absolute ml-3.5 min-w-[15px] rounded-full bg-indigo-500 p-[2px] text-center text-[10px] leading-3 text-white lg:-mt-1 lg:ml-2">
|
||||
{notifications.length > NOTIFICATIONS_PER_PAGE
|
||||
? `${NOTIFICATIONS_PER_PAGE}+`
|
||||
: notifications.length}
|
||||
</div>
|
||||
)}
|
||||
{privateUser && <UnseenNotificationsBubble privateUser={privateUser} />}
|
||||
<BellIcon className={clsx(props.className)} />
|
||||
</div>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
function UnseenNotificationsBubble(props: { privateUser: PrivateUser }) {
|
||||
const router = useRouter()
|
||||
const { privateUser } = props
|
||||
const [seen, setSeen] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (router.pathname.endsWith('notifications')) return setSeen(true)
|
||||
else setSeen(false)
|
||||
}, [router.pathname])
|
||||
|
||||
const notifications = useUnseenPreferredNotificationGroups(privateUser)
|
||||
if (!notifications || notifications.length === 0 || seen) {
|
||||
return <div />
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="-mt-0.75 absolute ml-3.5 min-w-[15px] rounded-full bg-indigo-500 p-[2px] text-center text-[10px] leading-3 text-white lg:-mt-1 lg:ml-2">
|
||||
{notifications.length > NOTIFICATIONS_PER_PAGE
|
||||
? `${NOTIFICATIONS_PER_PAGE}+`
|
||||
: notifications.length}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { listenForPrivateUser } from 'web/lib/firebase/users'
|
||||
import { notification_subscribe_types, PrivateUser } from 'common/user'
|
||||
import { Notification } from 'common/notification'
|
||||
import { listenForNotifications } from 'web/lib/firebase/notifications'
|
||||
import {
|
||||
getNotificationsQuery,
|
||||
listenForNotifications,
|
||||
} from 'web/lib/firebase/notifications'
|
||||
import { groupBy, map } from 'lodash'
|
||||
import { useFirestoreQuery } from '@react-query-firebase/firestore'
|
||||
|
||||
export type NotificationGroup = {
|
||||
notifications: Notification[]
|
||||
|
@ -13,15 +16,36 @@ export type NotificationGroup = {
|
|||
type: 'income' | 'normal'
|
||||
}
|
||||
|
||||
export function usePreferredGroupedNotifications(
|
||||
userId: string | undefined,
|
||||
options: { unseenOnly: boolean }
|
||||
) {
|
||||
// This doesn't listen for new notifications, use firebase listener for that
|
||||
export function usePreferredGroupedNotifications(privateUser: PrivateUser) {
|
||||
const [notificationGroups, setNotificationGroups] = useState<
|
||||
NotificationGroup[] | undefined
|
||||
>(undefined)
|
||||
const [notifications, setNotifications] = useState<Notification[]>([])
|
||||
const key = `notifications-${privateUser.id}-all`
|
||||
|
||||
const result = useFirestoreQuery(
|
||||
[key],
|
||||
getNotificationsQuery(privateUser.id, false),
|
||||
{
|
||||
// subscribe: false,
|
||||
// includeMetadataChanges: true,
|
||||
}
|
||||
)
|
||||
useEffect(() => {
|
||||
if (result.isLoading) return
|
||||
if (!result.data) return setNotifications([])
|
||||
const notifications = result.data.docs.map(
|
||||
(doc) => doc.data() as Notification
|
||||
)
|
||||
|
||||
const notificationsToShow = getAppropriateNotifications(
|
||||
notifications,
|
||||
privateUser.notificationPreferences
|
||||
).filter((n) => !n.isSeenOnHref)
|
||||
setNotifications(notificationsToShow)
|
||||
}, [privateUser.notificationPreferences, result.data, result.isLoading])
|
||||
|
||||
const notifications = usePreferredNotifications(userId, options)
|
||||
useEffect(() => {
|
||||
if (!notifications) return
|
||||
|
||||
|
@ -32,6 +56,20 @@ export function usePreferredGroupedNotifications(
|
|||
return notificationGroups
|
||||
}
|
||||
|
||||
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)
|
||||
}, [notifications])
|
||||
return notificationGroups
|
||||
}
|
||||
|
||||
export function groupNotifications(notifications: Notification[]) {
|
||||
let notificationGroups: NotificationGroup[] = []
|
||||
const notificationGroupsByDay = groupBy(notifications, (notification) =>
|
||||
|
@ -85,32 +123,17 @@ export function groupNotifications(notifications: Notification[]) {
|
|||
return notificationGroups
|
||||
}
|
||||
|
||||
export function usePreferredNotifications(
|
||||
userId: string | undefined,
|
||||
options: { unseenOnly: boolean; customHref?: string }
|
||||
export function useUnseenPreferredNotifications(
|
||||
privateUser: PrivateUser,
|
||||
options: { customHref?: string }
|
||||
) {
|
||||
const { unseenOnly, customHref } = options
|
||||
const [privateUser, setPrivateUser] = useState<PrivateUser | null>(null)
|
||||
const { customHref } = options
|
||||
const [notifications, setNotifications] = useState<Notification[]>([])
|
||||
const [userAppropriateNotifications, setUserAppropriateNotifications] =
|
||||
useState<Notification[]>([])
|
||||
listenForNotifications(privateUser.id, setNotifications, true)
|
||||
|
||||
useEffect(() => {
|
||||
if (userId) listenForPrivateUser(userId, setPrivateUser)
|
||||
}, [userId])
|
||||
|
||||
useEffect(() => {
|
||||
if (privateUser)
|
||||
return listenForNotifications(
|
||||
privateUser.id,
|
||||
setNotifications,
|
||||
unseenOnly
|
||||
)
|
||||
}, [privateUser, unseenOnly])
|
||||
|
||||
useEffect(() => {
|
||||
if (!privateUser) return
|
||||
|
||||
const notificationsToShow = getAppropriateNotifications(
|
||||
notifications,
|
||||
privateUser.notificationPreferences
|
||||
|
@ -118,7 +141,7 @@ export function usePreferredNotifications(
|
|||
customHref ? n.isSeenOnHref?.includes(customHref) : !n.isSeenOnHref
|
||||
)
|
||||
setUserAppropriateNotifications(notificationsToShow)
|
||||
}, [privateUser, notifications, customHref])
|
||||
}, [notifications, customHref, privateUser.notificationPreferences])
|
||||
|
||||
return userAppropriateNotifications
|
||||
}
|
||||
|
@ -131,7 +154,7 @@ const lessPriorityReasons = [
|
|||
// 'on_contract_with_users_shares_in',
|
||||
]
|
||||
|
||||
function getAppropriateNotifications(
|
||||
export function getAppropriateNotifications(
|
||||
notifications: Notification[],
|
||||
notificationPreferences?: notification_subscribe_types
|
||||
) {
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
import { collection, query, where } from 'firebase/firestore'
|
||||
import { collection, 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'
|
||||
|
||||
function getNotificationsQuery(userId: string, unseenOnly?: boolean) {
|
||||
export function getNotificationsQuery(userId: string, unseenOnly?: boolean) {
|
||||
const notifsCollection = collection(db, `/users/${userId}/notifications`)
|
||||
if (unseenOnly) return query(notifsCollection, where('isSeen', '==', false))
|
||||
return query(notifsCollection)
|
||||
if (unseenOnly)
|
||||
return query(
|
||||
notifsCollection,
|
||||
where('isSeen', '==', false),
|
||||
orderBy('createdTime', 'desc')
|
||||
)
|
||||
return query(notifsCollection, orderBy('createdTime', 'desc'))
|
||||
}
|
||||
|
||||
export function listenForNotifications(
|
||||
|
@ -19,6 +24,7 @@ export function listenForNotifications(
|
|||
(notifs) => {
|
||||
notifs.sort((n1, n2) => n2.createdTime - n1.createdTime)
|
||||
setNotifications(notifs)
|
||||
}
|
||||
},
|
||||
true
|
||||
)
|
||||
}
|
||||
|
|
|
@ -39,12 +39,13 @@ export function listenForValue<T>(
|
|||
|
||||
export function listenForValues<T>(
|
||||
query: Query,
|
||||
setValues: (values: T[]) => void
|
||||
setValues: (values: T[]) => void,
|
||||
enableCache?: boolean
|
||||
) {
|
||||
// Exclude cached snapshots so we only trigger on fresh data.
|
||||
// includeMetadataChanges ensures listener is called even when server data is the same as cached data.
|
||||
return onSnapshot(query, { includeMetadataChanges: true }, (snapshot) => {
|
||||
if (snapshot.metadata.fromCache) return
|
||||
if (snapshot.metadata.fromCache && !enableCache) return
|
||||
|
||||
const values = snapshot.docs.map((doc) => doc.data() as T)
|
||||
setValues(values)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Tabs } from 'web/components/layout/tabs'
|
||||
import { useUser } from 'web/hooks/use-user'
|
||||
import { usePrivateUser, useUser } from 'web/hooks/use-user'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { Notification, notification_source_types } from 'common/notification'
|
||||
import { Avatar, EmptyAvatar } from 'web/components/avatar'
|
||||
|
@ -9,7 +9,6 @@ import { Title } from 'web/components/title'
|
|||
import { doc, updateDoc } from 'firebase/firestore'
|
||||
import { db } from 'web/lib/firebase/init'
|
||||
import { CopyLinkDateTimeComponent } from 'web/components/feed/copy-link-date-time'
|
||||
import Custom404 from 'web/pages/404'
|
||||
import { UserLink } from 'web/components/user-page'
|
||||
import { notification_subscribe_types, PrivateUser } from 'common/user'
|
||||
import { Contract } from 'common/contract'
|
||||
|
@ -35,137 +34,144 @@ import { formatMoney } from 'common/util/format'
|
|||
import { groupPath } from 'web/lib/firebase/groups'
|
||||
import { UNIQUE_BETTOR_BONUS_AMOUNT } from 'common/numeric-constants'
|
||||
import { groupBy, sum, uniq } from 'lodash'
|
||||
import Custom404 from 'web/pages/404'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
|
||||
export const NOTIFICATIONS_PER_PAGE = 30
|
||||
const MULTIPLE_USERS_KEY = 'multipleUsers'
|
||||
|
||||
export default function Notifications() {
|
||||
const user = useUser()
|
||||
const [page, setPage] = useState(1)
|
||||
|
||||
const groupedNotifications = usePreferredGroupedNotifications(user?.id, {
|
||||
unseenOnly: false,
|
||||
})
|
||||
const [paginatedNotificationGroups, setPaginatedNotificationGroups] =
|
||||
useState<NotificationGroup[]>([])
|
||||
useEffect(() => {
|
||||
if (!groupedNotifications) return
|
||||
const start = (page - 1) * NOTIFICATIONS_PER_PAGE
|
||||
const end = start + NOTIFICATIONS_PER_PAGE
|
||||
const maxNotificationsToShow = groupedNotifications.slice(start, end)
|
||||
const remainingNotification = groupedNotifications.slice(end)
|
||||
for (const notification of remainingNotification) {
|
||||
if (notification.isSeen) break
|
||||
else setNotificationsAsSeen(notification.notifications)
|
||||
}
|
||||
setPaginatedNotificationGroups(maxNotificationsToShow)
|
||||
}, [groupedNotifications, page])
|
||||
|
||||
if (user === undefined) {
|
||||
return <LoadingIndicator />
|
||||
}
|
||||
if (user === null) {
|
||||
return <Custom404 />
|
||||
}
|
||||
const privateUser = usePrivateUser(user?.id)
|
||||
|
||||
if (!user) return <Custom404 />
|
||||
return (
|
||||
<Page>
|
||||
<div className={'p-2 sm:p-4'}>
|
||||
<Title text={'Notifications'} className={'hidden md:block'} />
|
||||
<Tabs
|
||||
labelClassName={'pb-2 pt-1 '}
|
||||
defaultIndex={0}
|
||||
tabs={[
|
||||
{
|
||||
title: 'Notifications',
|
||||
content: groupedNotifications ? (
|
||||
<div className={''}>
|
||||
{paginatedNotificationGroups.length === 0 &&
|
||||
"You don't have any notifications. Try changing your settings to see more."}
|
||||
{paginatedNotificationGroups.map((notification) =>
|
||||
notification.type === 'income' ? (
|
||||
<IncomeNotificationGroupItem
|
||||
notificationGroup={notification}
|
||||
key={notification.groupedById + notification.timePeriod}
|
||||
/>
|
||||
) : notification.notifications.length === 1 ? (
|
||||
<NotificationItem
|
||||
notification={notification.notifications[0]}
|
||||
key={notification.notifications[0].id}
|
||||
/>
|
||||
) : (
|
||||
<NotificationGroupItem
|
||||
notificationGroup={notification}
|
||||
key={notification.groupedById + notification.timePeriod}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
{groupedNotifications.length > NOTIFICATIONS_PER_PAGE && (
|
||||
<nav
|
||||
className="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6"
|
||||
aria-label="Pagination"
|
||||
>
|
||||
<div className="hidden sm:block">
|
||||
<p className="text-sm text-gray-700">
|
||||
Showing{' '}
|
||||
<span className="font-medium">
|
||||
{page === 1
|
||||
? page
|
||||
: (page - 1) * NOTIFICATIONS_PER_PAGE}
|
||||
</span>{' '}
|
||||
to{' '}
|
||||
<span className="font-medium">
|
||||
{page * NOTIFICATIONS_PER_PAGE}
|
||||
</span>{' '}
|
||||
of{' '}
|
||||
<span className="font-medium">
|
||||
{groupedNotifications.length}
|
||||
</span>{' '}
|
||||
results
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-1 justify-between sm:justify-end">
|
||||
<a
|
||||
href="#"
|
||||
className="relative inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50"
|
||||
onClick={() => page > 1 && setPage(page - 1)}
|
||||
>
|
||||
Previous
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
className="relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50"
|
||||
onClick={() =>
|
||||
page <
|
||||
groupedNotifications?.length /
|
||||
NOTIFICATIONS_PER_PAGE && setPage(page + 1)
|
||||
}
|
||||
>
|
||||
Next
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<LoadingIndicator />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Settings',
|
||||
content: (
|
||||
<div className={''}>
|
||||
<NotificationSettings />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<div>
|
||||
<Tabs
|
||||
labelClassName={'pb-2 pt-1 '}
|
||||
className={'mb-0 sm:mb-2'}
|
||||
defaultIndex={0}
|
||||
tabs={[
|
||||
{
|
||||
title: 'Notifications',
|
||||
content: privateUser ? (
|
||||
<NotificationsList privateUser={privateUser} />
|
||||
) : (
|
||||
<LoadingIndicator />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Settings',
|
||||
content: (
|
||||
<div className={''}>
|
||||
<NotificationSettings />
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
function NotificationsList(props: { privateUser: PrivateUser }) {
|
||||
const { privateUser } = props
|
||||
const [page, setPage] = useState(1)
|
||||
const allGroupedNotifications = usePreferredGroupedNotifications(privateUser)
|
||||
const [paginatedGroupedNotifications, setPaginatedGroupedNotifications] =
|
||||
useState<NotificationGroup[] | undefined>(undefined)
|
||||
|
||||
useEffect(() => {
|
||||
if (!allGroupedNotifications) return
|
||||
const start = (page - 1) * NOTIFICATIONS_PER_PAGE
|
||||
const end = start + NOTIFICATIONS_PER_PAGE
|
||||
const maxNotificationsToShow = allGroupedNotifications.slice(start, end)
|
||||
const remainingNotification = allGroupedNotifications.slice(end)
|
||||
for (const notification of remainingNotification) {
|
||||
if (notification.isSeen) break
|
||||
else setNotificationsAsSeen(notification.notifications)
|
||||
}
|
||||
setPaginatedGroupedNotifications(maxNotificationsToShow)
|
||||
}, [allGroupedNotifications, page])
|
||||
|
||||
if (!paginatedGroupedNotifications) return <LoadingIndicator />
|
||||
|
||||
return (
|
||||
<Col className={'min-h-screen'}>
|
||||
{paginatedGroupedNotifications.length === 0 &&
|
||||
"You don't have any notifications. Try changing your settings to see more."}
|
||||
{paginatedGroupedNotifications.map((notification) =>
|
||||
notification.type === 'income' ? (
|
||||
<IncomeNotificationGroupItem
|
||||
notificationGroup={notification}
|
||||
key={notification.groupedById + notification.timePeriod}
|
||||
/>
|
||||
) : notification.notifications.length === 1 ? (
|
||||
<NotificationItem
|
||||
notification={notification.notifications[0]}
|
||||
key={notification.notifications[0].id}
|
||||
/>
|
||||
) : (
|
||||
<NotificationGroupItem
|
||||
notificationGroup={notification}
|
||||
key={notification.groupedById + notification.timePeriod}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
{allGroupedNotifications &&
|
||||
allGroupedNotifications.length > NOTIFICATIONS_PER_PAGE && (
|
||||
<nav
|
||||
className="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6"
|
||||
aria-label="Pagination"
|
||||
>
|
||||
<div className="hidden sm:block">
|
||||
<p className="text-sm text-gray-700">
|
||||
Showing{' '}
|
||||
<span className="font-medium">
|
||||
{page === 1 ? page : (page - 1) * NOTIFICATIONS_PER_PAGE}
|
||||
</span>{' '}
|
||||
to{' '}
|
||||
<span className="font-medium">
|
||||
{page * NOTIFICATIONS_PER_PAGE}
|
||||
</span>{' '}
|
||||
of{' '}
|
||||
<span className="font-medium">
|
||||
{allGroupedNotifications.length}
|
||||
</span>{' '}
|
||||
results
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-1 justify-between sm:justify-end">
|
||||
<a
|
||||
href="#"
|
||||
className="relative inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50"
|
||||
onClick={() => page > 1 && setPage(page - 1)}
|
||||
>
|
||||
Previous
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
className="relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50"
|
||||
onClick={() =>
|
||||
page <
|
||||
allGroupedNotifications?.length / NOTIFICATIONS_PER_PAGE &&
|
||||
setPage(page + 1)
|
||||
}
|
||||
>
|
||||
Next
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
)}
|
||||
</Col>
|
||||
)
|
||||
}
|
||||
|
||||
function IncomeNotificationGroupItem(props: {
|
||||
notificationGroup: NotificationGroup
|
||||
className?: string
|
||||
|
|
Loading…
Reference in New Issue
Block a user