- {filtered.map((project) => (
+ {projects.map((project) => (
@@ -196,6 +214,41 @@ export function ProjectFilter({ projects, workspaces }: ProjectFilterProps) {
)}
+
+ {/* Pagination */}
+ {totalPages > 1 && (
+
+
+
+ Page {page} of {totalPages}
+
+
+
+ )}
>
);
}
diff --git a/app/(dashboard)/projects/[projectId]/page.tsx b/app/(dashboard)/projects/[projectId]/page.tsx
index c087536..395a17c 100644
--- a/app/(dashboard)/projects/[projectId]/page.tsx
+++ b/app/(dashboard)/projects/[projectId]/page.tsx
@@ -50,11 +50,17 @@ function formatRelativeTime(date: Date): string {
interface ProjectPageProps {
params: Promise<{ projectId: string }>;
+ searchParams: Promise<{ page?: string }>;
}
-export default async function ProjectPage({ params }: ProjectPageProps) {
+export default async function ProjectPage({ params, searchParams }: ProjectPageProps) {
const session = await auth();
const { projectId } = await params;
+ const resolvedSearchParams = await searchParams;
+
+ const page = Number(resolvedSearchParams?.page) || 1;
+ const pageSize = 20;
+ const skip = (page - 1) * pageSize;
// Fetch project with videos
const project = await db.project.findUnique({
@@ -66,19 +72,6 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
where: { userId: session?.user?.id || '' },
select: { role: true },
},
- videos: {
- orderBy: { position: 'asc' },
- include: {
- versions: {
- where: { isActive: true },
- take: 1,
- include: {
- _count: { select: { comments: true } },
- },
- },
- _count: { select: { versions: true } },
- },
- },
},
});
@@ -117,8 +110,33 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
redirect('/dashboard');
}
+ // Fetch videos separately utilizing bounds
+ const [paginatedVideos, totalVideos] = await Promise.all([
+ db.video.findMany({
+ where: { projectId: project.id },
+ skip,
+ take: pageSize,
+ orderBy: { position: 'asc' },
+ include: {
+ versions: {
+ where: { isActive: true },
+ take: 1,
+ include: {
+ _count: { select: { comments: true } },
+ },
+ },
+ _count: { select: { versions: true } },
+ },
+ }),
+ db.video.count({
+ where: { projectId: project.id }
+ })
+ ]);
+
+ const totalPages = Math.ceil(totalVideos / pageSize);
+
// Transform videos for VideoCard component
- const videos = project.videos.map((video: typeof project.videos[0]) => {
+ const videos = paginatedVideos.map((video) => {
const activeVersion = video.versions[0];
return {
id: video.id,
@@ -165,6 +183,8 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
canEdit={false}
isOwner={false}
workspaceRole={null}
+ totalPages={totalPages}
+ currentPage={page}
/>
@@ -190,6 +210,8 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
canEdit={canEdit}
isOwner={isOwner}
workspaceRole={workspaceRole}
+ totalPages={totalPages}
+ currentPage={page}
/>
);
diff --git a/app/(dashboard)/projects/[projectId]/project-content-client.tsx b/app/(dashboard)/projects/[projectId]/project-content-client.tsx
index bb4c15d..4f337b8 100644
--- a/app/(dashboard)/projects/[projectId]/project-content-client.tsx
+++ b/app/(dashboard)/projects/[projectId]/project-content-client.tsx
@@ -1,6 +1,7 @@
'use client';
-import { useState, useMemo } from 'react';
+import { useCallback } from 'react';
+import { useRouter, useSearchParams } from 'next/navigation';
import Link from 'next/link';
import {
Plus,
@@ -46,6 +47,8 @@ interface ProjectContentClientProps {
canEdit: boolean;
isOwner: boolean;
workspaceRole: string | null;
+ totalPages: number;
+ currentPage: number;
}
export function ProjectContentClient({
@@ -55,16 +58,32 @@ export function ProjectContentClient({
canEdit,
isOwner,
workspaceRole,
+ totalPages,
+ currentPage
}: ProjectContentClientProps) {
- const [sortOrder, setSortOrder] = useState