import AdaptableCard from '@/components/shared/AdaptableCard' import Container from '@/components/shared/Container' import Drawer from '@/components/ui/Drawer' import Button from '@/components/ui/Button' import NotificationChannels from '@/constants/notification-channel.enum' import { NotificationDto } from '@/proxy/notification/models' import { getList, updateReadAll } from '@/services/notification.service' import { useLocalization } from '@/utils/hooks/useLocalization' import dayjs from 'dayjs' import { groupBy } from '@/utils/collection' import { useCallback, useEffect, useState } from 'react' import Log from './components/Log' import LogFilter from './components/LogFilter' import PageTitle from '@/components/shared/PageTitle' import { DIR_RTL } from '@/constants/theme.constant' import { useStoreState } from '@/store' const itemsPerPage = 10 type NotificationGroups = Record const ActivityLog = () => { const { translate } = useLocalization() const [loading, setLoading] = useState(false) const [notifications, setNotifications] = useState({}) const [page, setPage] = useState(0) const [hasMore, setHasMore] = useState(false) const [isFilterDrawerOpen, setIsFilterDrawerOpen] = useState(false) const [markingRead, setMarkingRead] = useState(false) const direction = useStoreState((state) => state.theme.direction) const [filter, setFilter] = useState([ NotificationChannels.Desktop, NotificationChannels.Mail, NotificationChannels.Rocket, NotificationChannels.Sms, NotificationChannels.UiActivity, NotificationChannels.UiToast, NotificationChannels.WhatsApp, NotificationChannels.Telegram, ]) const fetchData = useCallback(async (isLoadmore: boolean = false) => { setLoading(true) try { const response = await getList({ maxResultCount: itemsPerPage, skipCount: page * itemsPerPage, sorting: 'CreationTime DESC', channels: filter, isListRequest: true, }) const items = response.data?.items ?? [] const currentItemCount = page * itemsPerPage + items.length setHasMore((response.data?.totalCount ?? 0) > currentItemCount) const logs = groupBy(items, (a) => dayjs(a.creationTime).format('YYYY-MM-DD')) if (isLoadmore) { setNotifications((prev) => { const next: NotificationGroups = { ...prev } for (const [key, value] of Object.entries(logs)) { // Sayfalama canli veri uzerinde calisir; araya yeni bildirim girdiginde ayni // kayit ikinci sayfada tekrar gelebilir. Id bazli eleme olmadan liste kaydi iki // kez cizer ve React ayni anahtari iki kez gorur. const existingIds = new Set((next[key] ?? []).map((item) => item.id)) next[key] = [ ...(next[key] ?? []), ...value.filter((item) => !existingIds.has(item.id)), ] } return next }) } else { setNotifications(logs) } } finally { setLoading(false) } }, [filter, page]) useEffect(() => { fetchData(page > 0) }, [fetchData, page]) /** * Ekranda görülen kayıtlar okundu işaretlenmeden rozetteki sayı düşmüyordu. İşaretleme * süzülen kanallarla sınırlıdır; sunucu iletilmemiş kayıtları zaten atlar. */ const handleMarkAllAsRead = async () => { setMarkingRead(true) try { await Promise.all(filter.map((channel) => updateReadAll(channel, true))) setPage(0) await fetchData() } finally { setMarkingRead(false) } } const handleFilterChange = (value: string[]) => { setPage(0) setNotifications({}) setHasMore(false) setFilter(value) setIsFilterDrawerOpen(false) } return (

{translate('::Abp.Identity.ActivityLogs')}

setPage((prev) => prev + 1)} >
setIsFilterDrawerOpen(false)} onRequestClose={() => setIsFilterDrawerOpen(false)} >
) } export default ActivityLog