import Avatar from '@/components/ui/Avatar' import Badge from '@/components/ui/Badge' import Button from '@/components/ui/Button' import Dropdown from '@/components/ui/Dropdown' import ScrollBar from '@/components/ui/ScrollBar' import Spinner from '@/components/ui/Spinner' import Tooltip from '@/components/ui/Tooltip' import { AVATAR_URL } from '@/constants/app.constant' import NotificationChannels from '@/constants/notification-channel.enum' import { ROUTES_ENUM } from '@/constants/route.constant' import { getList, updateRead, updateReadAll, updateSent, } from '@/proxy/notification/notification.service' import { useStoreState } from '@/store' import withHeaderItem from '@/utils/hoc/withHeaderItem' import { useLocalization } from '@/utils/hooks/useLocalization' import useResponsive from '@/utils/hooks/useResponsive' import useThemeClass from '@/utils/hooks/useThemeClass' import isLastChild from '@/utils/isLastChild' import classNames from 'classnames' import dayjs from 'dayjs' import relativeTime from 'dayjs/plugin/relativeTime' import { useCallback, useEffect, useRef, useState } from 'react' import { HiOutlineBell, HiOutlineMailOpen } from 'react-icons/hi' import { Link } from 'react-router-dom' import { Notification as Notify, toast } from '../ui' dayjs.extend(relativeTime) type NotificationList = { id: string creatorId: string tenantId?: string notificationType: string message: string date: string readed: boolean } const notificationHeight = 'h-72' const notificationInterval = 120000 const notificationTypeAvatar = (creatorId: string, tenantId?: string) => { return } const NotificationToggle = ({ className, unreadCount, }: { className?: string unreadCount: number }) => { return (
{unreadCount > 0 ? ( ) : ( )}
) } const _Notification = ({ className }: { className?: string }) => { const { translate } = useLocalization() const [notificationList, setNotificationList] = useState([]) const [unreadNotificationCount, setUnreadNotificationCount] = useState(0) const [noResult, setNoResult] = useState(false) const [loading, setLoading] = useState(false) const [toastNotificationList, setToastNotificationList] = useState([]) const toastNotificationInterval = useRef() const [desktopNotificationList, setDesktopNotificationList] = useState([]) const desktopNotificationInterval = useRef() const { bgTheme } = useThemeClass() const { larger } = useResponsive() const direction = useStoreState((state) => state.theme.direction) const tabHasFocus = useStoreState((a) => a.base.common.tabHasFocus) const getReactNotificationCount = useCallback(async () => { const resp = await getList({ channels: [NotificationChannels.UiActivity], isListRequest: false, isRead: false, maxResultCount: 1, }) setUnreadNotificationCount(resp.data?.totalCount ?? 0) }, [setUnreadNotificationCount]) useEffect(() => { getReactNotificationCount() var intervalId = setInterval(() => { getReactNotificationCount() }, notificationInterval) return () => { clearInterval(intervalId) } }, [getReactNotificationCount]) const onNotificationOpen = useCallback(async () => { const currentUnread = notificationList.filter((a) => !a.readed).length if (currentUnread !== unreadNotificationCount) { setLoading(true) const resp = await getList({ channels: [NotificationChannels.UiActivity], isListRequest: false, maxResultCount: 1000, }) const items = resp.data.items ?? [] for (const notification of items) { await updateSent(notification.id, true) } const newNotificationList = items.map( (a) => ({ id: a.id, notificationType: a.notificationType, date: a.creationTime.toLocaleString(), message: a.message, creatorId: a.creatorId, tenantId: a.tenantId, readed: a.isRead, }) as NotificationList, ) setLoading(false) setNotificationList(newNotificationList) setNoResult(newNotificationList.length == 0) } }, [notificationList, setLoading, unreadNotificationCount]) const onMarkAllAsRead = useCallback(async () => { await updateReadAll(NotificationChannels.UiToast, true) const list = notificationList.map((item: NotificationList) => { if (!item.readed) { item.readed = true } return item }) setNotificationList(list) setUnreadNotificationCount(0) }, [notificationList]) const onMarkAsRead = useCallback( async (id: string) => { await updateRead(id, true) const list = notificationList.map((item) => { if (item.id === id) { item.readed = true } return item }) setNotificationList(list) const unreadCount = notificationList.filter((item) => !item.readed).length setUnreadNotificationCount(unreadCount) }, [notificationList], ) // Toast const getToastNotifications = async () => { const resp = await getList({ channels: [NotificationChannels.UiToast], isListRequest: false, maxResultCount: 1000, }) const items = resp.data.items ?? [] const newNotificationList = items.filter( (a) => !toastNotificationList.includes(a.id) && !a.isSent, ) setToastNotificationList(newNotificationList.map((a) => a.id)) for (const notification of newNotificationList) { toast.push( { await updateRead(notification.id, true) }} > {notification.message} , { placement: 'bottom-end', }, ) await updateSent(notification.id, true) } setToastNotificationList([]) } useEffect(() => { toastNotificationInterval.current = setInterval(async () => { if (tabHasFocus) { await getToastNotifications() } }, notificationInterval) return () => { clearInterval(toastNotificationInterval.current) } }, [toastNotificationList, tabHasFocus]) //Desktop const getDesktopNotifications = async () => { const resp = await getList({ channels: [NotificationChannels.Desktop], isListRequest: false, maxResultCount: 1000, }) const items = resp.data.items ?? [] const newNotificationList = items.filter( (a) => !desktopNotificationList.includes(a.id) && !a.isSent, ) setDesktopNotificationList(newNotificationList.map((a) => a.id)) for (const notification of newNotificationList) { var options = { body: notification.message, dir: 'ltr', } as NotificationOptions new window.Notification(notification.notificationType, options) await updateSent(notification.id, true) } setDesktopNotificationList([]) } useEffect(() => { desktopNotificationInterval.current = setInterval(async () => { await getDesktopNotifications() }, notificationInterval) return () => { clearInterval(desktopNotificationInterval.current) } }, [desktopNotificationList]) return ( } menuClass="p-0 min-w-[280px] md:min-w-[340px]" placement={larger.md ? 'bottom-end' : 'bottom-center'} onOpen={onNotificationOpen} >
{translate('::Abp.Identity.ActivityLogs.Notifications')}
{notificationList.length > 0 && notificationList.map((item, index) => (
onMarkAsRead(item.id)} >
{notificationTypeAvatar(item.creatorId, item.tenantId)}
{item.notificationType && ( {item.notificationType} )}
{item.message}
{dayjs(item.date).fromNow()}
))} {loading && (
)} {noResult && (
no-notification
No notifications!

Please Try again later

)}
{translate('::Abp.Identity.ActivityLogs.ViewAllActivity')}
) } const Notification = withHeaderItem(_Notification) export default Notification