ActivityLog düzenlemesi

This commit is contained in:
Sedat ÖZTÜRK 2026-03-24 09:38:55 +03:00
parent a7e8d7995b
commit cf6ded1105
3 changed files with 90 additions and 47 deletions

View file

@ -1,5 +1,7 @@
import AdaptableCard from '@/components/shared/AdaptableCard' import AdaptableCard from '@/components/shared/AdaptableCard'
import Container from '@/components/shared/Container' 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 NotificationChannels from '@/constants/notification-channel.enum'
import { NotificationDto } from '@/proxy/notification/models' import { NotificationDto } from '@/proxy/notification/models'
import { getList } from '@/services/notification.service' import { getList } from '@/services/notification.service'
@ -9,13 +11,14 @@ import { Dictionary } from 'lodash'
import forOwn from 'lodash/forOwn' import forOwn from 'lodash/forOwn'
import groupBy from 'lodash/groupBy' import groupBy from 'lodash/groupBy'
import has from 'lodash/has' import has from 'lodash/has'
import isEmpty from 'lodash/isEmpty'
import merge from 'lodash/merge' import merge from 'lodash/merge'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import Log from './components/Log' import Log from './components/Log'
import LogFilter from './components/LogFilter' import LogFilter from './components/LogFilter'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
import { APP_NAME } from '@/constants/app.constant' import { APP_NAME } from '@/constants/app.constant'
import { DIR_RTL } from '@/constants/theme.constant'
import { useStoreState } from '@/store'
const itemsPerPage = 10 const itemsPerPage = 10
@ -26,12 +29,13 @@ const ActivityLog = () => {
const [notifications, setNotifications] = useState<Dictionary<NotificationDto[]>>({}) const [notifications, setNotifications] = useState<Dictionary<NotificationDto[]>>({})
const [page, setPage] = useState(0) const [page, setPage] = useState(0)
const [hasMore, setHasMore] = useState(false) const [hasMore, setHasMore] = useState(false)
const [isFilterDrawerOpen, setIsFilterDrawerOpen] = useState(false)
const direction = useStoreState((state) => state.theme.direction)
const [filter, setFilter] = useState<string[]>([ const [filter, setFilter] = useState<string[]>([
NotificationChannels.Desktop, NotificationChannels.Desktop,
NotificationChannels.Mail, NotificationChannels.Mail,
NotificationChannels.Rocket, NotificationChannels.Rocket,
NotificationChannels.Sms, NotificationChannels.Sms,
NotificationChannels.Telegram,
NotificationChannels.UiActivity, NotificationChannels.UiActivity,
NotificationChannels.UiToast, NotificationChannels.UiToast,
NotificationChannels.WhatsApp, NotificationChannels.WhatsApp,
@ -67,18 +71,16 @@ const ActivityLog = () => {
} }
useEffect(() => { useEffect(() => {
if (isEmpty(notifications)) { fetchData(page > 0)
fetchData() }, [page, filter])
const handleFilterChange = (value: string[]) => {
setPage(0)
setNotifications({})
setHasMore(false)
setFilter(value)
setIsFilterDrawerOpen(false)
} }
}, [])
useEffect(() => {
fetchData(true)
}, [page])
useEffect(() => {
fetchData()
}, [filter])
return ( return (
<Container> <Container>
@ -88,19 +90,53 @@ const ActivityLog = () => {
defaultTitle={APP_NAME} defaultTitle={APP_NAME}
></Helmet> ></Helmet>
<AdaptableCard> <AdaptableCard className="overflow-hidden">
<div className="grid lg:grid-cols-5 gap-8"> <div className="w-full">
<div className="col-span-4"> <div className="mb-5 flex items-center justify-between gap-3">
<h3 className="mb-6">{translate('::Abp.Identity.ActivityLogs')}</h3> <h3 className="text-xl font-semibold md:text-2xl">
{translate('::Abp.Identity.ActivityLogs')}
</h3>
<Button
className="lg:hidden"
size="sm"
variant="twoTone"
onClick={() => setIsFilterDrawerOpen(true)}
>
{translate('::Abp.Identity.ActivityLogs.Filters')}
</Button>
</div>
<div className="grid grid-cols-1 gap-6 lg:grid-cols-[minmax(0,1fr)_340px]">
<div className="min-w-0 rounded-xl border border-gray-200 bg-white p-4 lg:p-6">
<Log <Log
notifications={notifications} notifications={notifications}
isLoading={loading} isLoading={loading}
onLoadMore={() => setPage(page + 1)} onLoadMore={() => setPage((prev) => prev + 1)}
loadable={hasMore} loadable={hasMore}
></Log> ></Log>
</div> </div>
<LogFilter filter={filter} onFilterChange={(value: string[]) => setFilter(value)} />
<div className="hidden lg:block">
<LogFilter filter={filter} onFilterChange={handleFilterChange} useAffix />
</div> </div>
</div>
</div>
<Drawer
title={translate('::Abp.Identity.ActivityLogs.Filters')}
isOpen={isFilterDrawerOpen}
width={340}
placement={direction === DIR_RTL ? 'right' : 'left'}
onClose={() => setIsFilterDrawerOpen(false)}
onRequestClose={() => setIsFilterDrawerOpen(false)}
>
<LogFilter
filter={filter}
onFilterChange={handleFilterChange}
useAffix={false}
className="border-none p-0"
/>
</Drawer>
</AdaptableCard> </AdaptableCard>
</Container> </Container>
) )

View file

@ -28,7 +28,7 @@ const Log = ({
return ( return (
<Loading type="cover" loading={isLoading}> <Loading type="cover" loading={isLoading}>
<div className="max-w-[900px]"> <div className="w-full">
{keys(notifications).map((group) => ( {keys(notifications).map((group) => (
<div key={group} className="mb-8"> <div key={group} className="mb-8">
<div className="mb-4 font-semibold uppercase"> <div className="mb-4 font-semibold uppercase">

View file

@ -15,7 +15,6 @@ const ticketCheckboxes = [
{ label: NotificationChannels.UiActivity, value: NotificationChannels.UiActivity }, { label: NotificationChannels.UiActivity, value: NotificationChannels.UiActivity },
{ label: NotificationChannels.UiToast, value: NotificationChannels.UiToast }, { label: NotificationChannels.UiToast, value: NotificationChannels.UiToast },
{ label: NotificationChannels.WhatsApp, value: NotificationChannels.WhatsApp }, { label: NotificationChannels.WhatsApp, value: NotificationChannels.WhatsApp },
{ label: NotificationChannels.Telegram, value: NotificationChannels.Telegram },
] ]
const CategoryTitle = ({ children, className }: CategoryTitleProps) => { const CategoryTitle = ({ children, className }: CategoryTitleProps) => {
@ -34,16 +33,19 @@ const CategoryTitle = ({ children, className }: CategoryTitleProps) => {
const LogFilter = ({ const LogFilter = ({
filter, filter,
onFilterChange, onFilterChange,
useAffix = true,
className,
}: { }: {
filter: string[] filter: string[]
onFilterChange: (value: string[]) => void onFilterChange: (value: string[]) => void
useAffix?: boolean
className?: string
}) => { }) => {
const { translate } = useLocalization() const { translate } = useLocalization()
return ( const content = (
<div> <div className={classNames('rounded-xl border border-gray-200 bg-white p-4', className)}>
<Affix className="hidden lg:block" offset={80}> <h5 className="mb-4 text-base font-semibold">{translate('::Abp.Identity.ActivityLogs.Filters')}</h5>
<h5 className="mb-4">{translate('::Abp.Identity.ActivityLogs.Filters')}</h5>
<Checkbox.Group <Checkbox.Group
vertical vertical
value={filter} value={filter}
@ -51,18 +53,23 @@ const LogFilter = ({
onFilterChange(value as string[]) onFilterChange(value as string[])
}} }}
> >
<CategoryTitle className="mb-3"> <CategoryTitle className="mb-3 text-gray-500">
{translate('::Abp.Identity.ActivityLogs.Channels')} {translate('::Abp.Identity.ActivityLogs.Channels')}
</CategoryTitle> </CategoryTitle>
{ticketCheckboxes.map((checkbox) => ( {ticketCheckboxes.map((checkbox) => (
<Checkbox key={checkbox.value} className="mb-4" value={checkbox.value}> <Checkbox key={checkbox.value} className="mb-3" value={checkbox.value}>
{checkbox.label} {checkbox.label}
</Checkbox> </Checkbox>
))} ))}
</Checkbox.Group> </Checkbox.Group>
</Affix>
</div> </div>
) )
if (useAffix) {
return <Affix offset={80}>{content}</Affix>
}
return content
} }
export default LogFilter export default LogFilter