110 lines
3.3 KiB
TypeScript
110 lines
3.3 KiB
TypeScript
|
|
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
|