diff --git a/README.md b/README.md
index acbbda9..b0004fd 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ Currently, there is no documentation or wiki available but there will be one add
This will be published on the site some time soon but for now, the roadmap will be listed here.
- [ ] Finish adding started at date feature
-- [ ] Pagination for Audit Logs page
+- [x] Pagination for Audit Logs page
- [ ] Board sorting options (Boards Page)
- [ ] Add real-time collaboration
- [ ] Add end-to-end Database encryption (for customer data such as card titles and descriptions, and subscription information)
diff --git a/app/(platform)/(dashboard)/organization/[organizationId]/activity/_components/activity-list.tsx b/app/(platform)/(dashboard)/organization/[organizationId]/activity/_components/activity-list.tsx
index 24c06b6..6423e0d 100644
--- a/app/(platform)/(dashboard)/organization/[organizationId]/activity/_components/activity-list.tsx
+++ b/app/(platform)/(dashboard)/organization/[organizationId]/activity/_components/activity-list.tsx
@@ -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 (
-
-
- No activity found inside this organization
-
- {auditLogs.map((log) => (
-
- ))}
-
+
+
+
+ No activity found inside this organization
+
+ {auditLogs.map((log) => (
+
+ ))}
+
+
+
);
};
-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(
+
+
+ {i}
+
+
+ );
+ }
+ } else {
+ // Always show first page
+ pageNumbers.push(
+
+
+ 1
+
+
+ );
+
+ // Show ellipsis if current page is more than 3
+ if (currentPage > 3) {
+ pageNumbers.push(
+
+
+
+ );
+ }
+
+ // 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(
+
+
+ {i}
+
+
+ );
+ }
+
+ // Show ellipsis if current page is less than totalPages - 2
+ if (currentPage < totalPages - 2) {
+ pageNumbers.push(
+
+
+
+ );
+ }
+
+ // Always show last page
+ pageNumbers.push(
+
+
+ {totalPages}
+
+
+ );
+ }
+
+ return pageNumbers;
+ };
+
return (
-
-
-
-
-
-
-
+
+
+ {currentPage > 1 && (
+
+
+
+ )}
+ {renderPageNumbers()}
+ {currentPage < totalPages && (
+
+
+
+ )}
+
+
);
};
diff --git a/app/(platform)/(dashboard)/organization/[organizationId]/activity/page.tsx b/app/(platform)/(dashboard)/organization/[organizationId]/activity/page.tsx
index 731c31d..343d485 100644
--- a/app/(platform)/(dashboard)/organization/[organizationId]/activity/page.tsx
+++ b/app/(platform)/(dashboard)/organization/[organizationId]/activity/page.tsx
@@ -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 (
);
};
export default ActivityPage;
+
+const ActivityListSkeleton = () => {
+ return (
+
+
+
+
+
+
+
+ );
+};
diff --git a/components/ui/pagination.tsx b/components/ui/pagination.tsx
index 902d603..1c0d153 100644
--- a/components/ui/pagination.tsx
+++ b/components/ui/pagination.tsx
@@ -1,5 +1,6 @@
import * as React from 'react';
import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';
+import Link from 'next/link';
import { cn } from '@/lib/utils';
import { ButtonProps, buttonVariants } from '@/components/ui/button';
@@ -37,7 +38,7 @@ PaginationItem.displayName = 'PaginationItem';
type PaginationLinkProps = {
isActive?: boolean;
} & Pick &
- React.ComponentProps<'a'>;
+ React.ComponentProps;
const PaginationLink = ({
className,
@@ -45,7 +46,7 @@ const PaginationLink = ({
size = 'icon',
...props
}: PaginationLinkProps) => (
-