Added Pagination to Audit Log Page

This commit is contained in:
Ahmad 2024-11-01 22:07:52 -04:00
parent 10c54df886
commit c9313ff5f0
No known key found for this signature in database
GPG key ID: 8FD8A93530D182BF
4 changed files with 198 additions and 44 deletions

View file

@ -1,45 +1,144 @@
import { auth } from '@clerk/nextjs/server';
import { redirect } from 'next/navigation';
'use client';
import { db } from '@/lib/db';
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from '@/components/ui/pagination';
import { ActivityItem } from '@/components/activity-item';
import { Skeleton } from '@/components/ui/skeleton';
export const ActivityList = async () => {
const { orgId } = await auth();
if (!orgId) redirect('/select-org');
const auditLogs = await db.auditLog.findMany({
where: {
orgId,
},
orderBy: {
createdAt: 'desc',
},
cacheStrategy: { ttl: 30, swr: 60 },
});
import { AuditLog } from '@prisma/client';
export const ActivityList = ({
totalPages,
currentPage,
auditLogs,
}: {
totalPages: number;
currentPage: number;
auditLogs: AuditLog[];
}) => {
return (
<ol className='mt-4 space-y-4'>
<p className='hidden text-center text-xs text-muted-foreground last:block'>
No activity found inside this organization
</p>
{auditLogs.map((log) => (
<ActivityItem key={log.id} data={log} />
))}
</ol>
<div>
<ol className='mt-4 space-y-4'>
<p className='hidden text-center text-xs text-muted-foreground last:block'>
No activity found inside this organization
</p>
{auditLogs.map((log) => (
<ActivityItem key={log.id} data={log} />
))}
</ol>
<ActivityListPagination
totalPages={totalPages}
currentPage={currentPage}
/>
</div>
);
};
ActivityList.Skeleton = function ActivityListSkeleton() {
const ActivityListPagination = ({
totalPages,
currentPage,
}: {
totalPages: number;
currentPage: number;
}) => {
const renderPageNumbers = () => {
const pageNumbers = [];
const maxVisiblePages = 5;
if (totalPages <= maxVisiblePages) {
for (let i = 1; i <= totalPages; i++) {
pageNumbers.push(
<PaginationItem key={i}>
<PaginationLink
href={`activity?page=${i}`}
isActive={currentPage === i}
>
{i}
</PaginationLink>
</PaginationItem>
);
}
} else {
// Always show first page
pageNumbers.push(
<PaginationItem key={1}>
<PaginationLink href='activity?page=1' isActive={currentPage === 1}>
1
</PaginationLink>
</PaginationItem>
);
// Show ellipsis if current page is more than 3
if (currentPage > 3) {
pageNumbers.push(
<PaginationItem key='ellipsis-start'>
<PaginationEllipsis />
</PaginationItem>
);
}
// Show current page and surrounding pages
const startPage = Math.max(2, currentPage - 1);
const endPage = Math.min(totalPages - 1, currentPage + 1);
for (let i = startPage; i <= endPage; i++) {
pageNumbers.push(
<PaginationItem key={i}>
<PaginationLink
href={`activity?page=${i}`}
isActive={currentPage === i}
>
{i}
</PaginationLink>
</PaginationItem>
);
}
// Show ellipsis if current page is less than totalPages - 2
if (currentPage < totalPages - 2) {
pageNumbers.push(
<PaginationItem key='ellipsis-end'>
<PaginationEllipsis />
</PaginationItem>
);
}
// Always show last page
pageNumbers.push(
<PaginationItem key={totalPages}>
<PaginationLink
href={`activity?page=${totalPages}`}
isActive={currentPage === totalPages}
>
{totalPages}
</PaginationLink>
</PaginationItem>
);
}
return pageNumbers;
};
return (
<ol className='mt-4 space-y-4'>
<Skeleton className='h-14 w-[80%]' />
<Skeleton className='h-14 w-[50%]' />
<Skeleton className='h-14 w-[70%]' />
<Skeleton className='h-14 w-[80%]' />
<Skeleton className='h-14 w-[75%]' />
</ol>
<Pagination>
<PaginationContent>
{currentPage > 1 && (
<PaginationItem>
<PaginationPrevious href={`activity?page=${currentPage - 1}`} />
</PaginationItem>
)}
{renderPageNumbers()}
{currentPage < totalPages && (
<PaginationItem>
<PaginationNext href={`activity?page=${currentPage + 1}`} />
</PaginationItem>
)}
</PaginationContent>
</Pagination>
);
};

View file

@ -1,23 +1,77 @@
import { auth } from '@clerk/nextjs/server';
import { redirect } from 'next/navigation';
import { Suspense } from 'react';
import { Separator } from '@/components/ui/separator';
import { Info } from '../_components/info';
import { ActivityList } from './_components/activity-list';
import { checkSubscription } from '@/lib/subscription';
const ActivityPage = async () => {
import { Separator } from '@/components/ui/separator';
import { checkSubscription } from '@/lib/subscription';
import { db } from '@/lib/db';
import { Skeleton } from '@/components/ui/skeleton';
const ActivityPage = async ({
searchParams,
}: {
searchParams: { [key: string]: string | undefined };
}) => {
const isPro = await checkSubscription();
const { orgId } = await auth();
const params = await searchParams;
const currentPage = Number(params.page);
const limit = 10;
if (!orgId) redirect('/select-org');
if (!currentPage || currentPage < 1) redirect('activity?page=1');
const skip = (currentPage - 1) * limit;
const auditLogs = await db.auditLog.findMany({
where: {
orgId,
},
orderBy: {
createdAt: 'desc',
},
skip,
take: limit,
cacheStrategy: { ttl: 30, swr: 60 },
});
const totalCount = await db.auditLog.count({
where: {
orgId,
},
cacheStrategy: { ttl: 30, swr: 60 },
});
const totalPages = Math.ceil(totalCount / limit);
return (
<div className='w-full'>
<Info isPro={isPro} />
<Separator className='my-2' />
<Suspense fallback={<ActivityList.Skeleton />}>
<ActivityList />
<Suspense fallback={<ActivityListSkeleton />}>
<ActivityList
totalPages={totalPages}
currentPage={currentPage}
auditLogs={auditLogs}
/>
</Suspense>
</div>
);
};
export default ActivityPage;
const ActivityListSkeleton = () => {
return (
<ol className='mt-4 space-y-4'>
<Skeleton className='h-14 w-[80%]' />
<Skeleton className='h-14 w-[50%]' />
<Skeleton className='h-14 w-[70%]' />
<Skeleton className='h-14 w-[80%]' />
<Skeleton className='h-14 w-[75%]' />
</ol>
);
};