sozsoft-platform/ui/src/views/admin/activityLog/ActivityLog.tsx

110 lines
3.3 KiB
TypeScript
Raw Normal View History

2026-02-24 20:44:16 +00:00
import AdaptableCard from '@/components/shared/AdaptableCard'
import Container from '@/components/shared/Container'
import NotificationChannels from '@/constants/notification-channel.enum'
import { NotificationDto } from '@/proxy/notification/models'
import { getList } from '@/services/notification.service'
import { useLocalization } from '@/utils/hooks/useLocalization'
import dayjs from 'dayjs'
import { Dictionary } from 'lodash'
import forOwn from 'lodash/forOwn'
import groupBy from 'lodash/groupBy'
import has from 'lodash/has'
import isEmpty from 'lodash/isEmpty'
import merge from 'lodash/merge'
import { useEffect, useState } from 'react'
import Log from './components/Log'
import LogFilter from './components/LogFilter'
import { Helmet } from 'react-helmet'
import { APP_NAME } from '@/constants/app.constant'
const itemsPerPage = 10
const ActivityLog = () => {
const { translate } = useLocalization()
const [loading, setLoading] = useState(false)
const [notifications, setNotifications] = useState<Dictionary<NotificationDto[]>>({})
const [page, setPage] = useState(0)
const [hasMore, setHasMore] = useState(false)
const [filter, setFilter] = useState<string[]>([
NotificationChannels.Desktop,
NotificationChannels.Mail,
NotificationChannels.Rocket,
NotificationChannels.Sms,
NotificationChannels.Telegram,
NotificationChannels.UiActivity,
NotificationChannels.UiToast,
NotificationChannels.WhatsApp,
])
const fetchData = async (isLoadmore: boolean = false) => {
setLoading(true)
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) {
forOwn(notifications, function (value, key) {
if (has(logs, key)) {
notifications[key] = [...notifications[key], ...logs[key]]
delete logs[key]
}
})
setNotifications(merge(notifications, logs))
} else {
setNotifications(logs)
}
setLoading(false)
}
useEffect(() => {
if (isEmpty(notifications)) {
fetchData()
}
}, [])
useEffect(() => {
fetchData(true)
}, [page])
useEffect(() => {
fetchData()
}, [filter])
return (
<Container>
<Helmet
titleTemplate={`%s | ${APP_NAME}`}
title={translate('::' + 'Abp.Identity.ActivityLogs')}
defaultTitle={APP_NAME}
></Helmet>
<AdaptableCard>
<div className="grid lg:grid-cols-5 gap-8">
<div className="col-span-4">
<h3 className="mb-6">{translate('::Abp.Identity.ActivityLogs')}</h3>
<Log
notifications={notifications}
isLoading={loading}
onLoadMore={() => setPage(page + 1)}
loadable={hasMore}
></Log>
</div>
<LogFilter filter={filter} onFilterChange={(value: string[]) => setFilter(value)} />
</div>
</AdaptableCard>
</Container>
)
}
export default ActivityLog