33import type { Project } from "@/api/projects" ;
44import type { Team } from "@/api/team" ;
55import { ProjectAvatar } from "@/components/blocks/Avatars/ProjectAvatar" ;
6+ import { PaginationButtons } from "@/components/pagination-buttons" ;
67import { CopyTextButton } from "@/components/ui/CopyTextButton" ;
78import { Button } from "@/components/ui/button" ;
89import {
@@ -33,22 +34,24 @@ import {
3334import Link from "next/link" ;
3435import { useMemo , useState } from "react" ;
3536
36- type SortById = "name" | "createdAt" | "totalConnections " ;
37+ type SortById = "name" | "createdAt" | "monthlyActiveUsers " ;
3738
38- type ProjectWithTotalConnections = Project & { totalConnections : number } ;
39+ export type ProjectWithAnalytics = Project & {
40+ monthlyActiveUsers : number ;
41+ } ;
3942
4043export function TeamProjectsPage ( props : {
41- projects : ProjectWithTotalConnections [ ] ;
44+ projects : ProjectWithAnalytics [ ] ;
4245 team : Team ;
4346} ) {
4447 const { projects } = props ;
4548 const [ searchTerm , setSearchTerm ] = useState ( "" ) ;
46- const [ sortBy , setSortBy ] = useState < SortById > ( "totalConnections " ) ;
49+ const [ sortBy , setSortBy ] = useState < SortById > ( "monthlyActiveUsers " ) ;
4750 const [ isCreateProjectDialogOpen , setIsCreateProjectDialogOpen ] =
4851 useState ( false ) ;
4952 const router = useDashboardRouter ( ) ;
5053
51- const projectsToShow = useMemo ( ( ) => {
54+ const sortedProjects = useMemo ( ( ) => {
5255 let _projectsToShow = ! searchTerm
5356 ? projects
5457 : projects . filter (
@@ -68,15 +71,25 @@ export function TeamProjectsPage(props: {
6871 ( a , b ) =>
6972 new Date ( b . createdAt ) . getTime ( ) - new Date ( a . createdAt ) . getTime ( ) ,
7073 ) ;
71- } else if ( sortBy === "totalConnections " ) {
74+ } else if ( sortBy === "monthlyActiveUsers " ) {
7275 _projectsToShow = _projectsToShow . sort (
73- ( a , b ) => b . totalConnections - a . totalConnections ,
76+ ( a , b ) => b . monthlyActiveUsers - a . monthlyActiveUsers ,
7477 ) ;
7578 }
7679
7780 return _projectsToShow ;
7881 } , [ searchTerm , sortBy , projects ] ) ;
7982
83+ const pageSize = 8 ;
84+ const [ page , setPage ] = useState ( 1 ) ;
85+ const paginatedProjects = sortedProjects . slice (
86+ ( page - 1 ) * pageSize ,
87+ page * pageSize ,
88+ ) ;
89+
90+ const showPagination = sortedProjects . length > pageSize ;
91+ const totalPages = Math . ceil ( sortedProjects . length / pageSize ) ;
92+
8093 return (
8194 < div className = "flex grow flex-col" >
8295 { /* Filters + Add New */ }
@@ -94,7 +107,7 @@ export function TeamProjectsPage(props: {
94107 < div className = "h-6" />
95108
96109 { /* Projects */ }
97- { projectsToShow . length === 0 ? (
110+ { paginatedProjects . length === 0 ? (
98111 < >
99112 { searchTerm !== "" ? (
100113 < div className = "flex min-h-[450px] grow items-center justify-center rounded-lg border border-border" >
@@ -120,7 +133,7 @@ export function TeamProjectsPage(props: {
120133 </ >
121134 ) : (
122135 < div className = "grid grid-cols-1 gap-5 md:grid-cols-2" >
123- { projectsToShow . map ( ( project ) => {
136+ { paginatedProjects . map ( ( project ) => {
124137 return (
125138 < ProjectCard
126139 key = { project . id }
@@ -132,6 +145,16 @@ export function TeamProjectsPage(props: {
132145 </ div >
133146 ) }
134147
148+ { showPagination && (
149+ < div className = "py-6" >
150+ < PaginationButtons
151+ activePage = { page }
152+ onPageClick = { setPage }
153+ totalPages = { totalPages }
154+ />
155+ </ div >
156+ ) }
157+
135158 < LazyCreateAPIKeyDialog
136159 open = { isCreateProjectDialogOpen }
137160 onOpenChange = { setIsCreateProjectDialogOpen }
@@ -148,7 +171,7 @@ export function TeamProjectsPage(props: {
148171}
149172
150173function ProjectCard ( props : {
151- project : ProjectWithTotalConnections ;
174+ project : ProjectWithAnalytics ;
152175 team_slug : string ;
153176} ) {
154177 const { project, team_slug } = props ;
@@ -160,7 +183,7 @@ function ProjectCard(props: {
160183 { /* TODO - set image */ }
161184 < ProjectAvatar className = "size-10 rounded-full" src = "" />
162185
163- < div className = "flex-grow flex-col gap-1.5 " >
186+ < div className = "flex flex -grow flex-col gap-1" >
164187 < Link
165188 className = "group static before:absolute before:top-0 before:right-0 before:bottom-0 before:left-0 before:z-0"
166189 // remove /connect when we have overview page
@@ -170,8 +193,8 @@ function ProjectCard(props: {
170193 </ Link >
171194
172195 < p className = "flex items-center gap-1 text-muted-foreground text-sm" >
173- < span > { project . totalConnections } </ span >
174- Total Users
196+ < span > { project . monthlyActiveUsers } </ span >
197+ Monthly Active Users
175198 </ p >
176199 </ div >
177200
@@ -256,11 +279,11 @@ function SelectBy(props: {
256279 value : SortById ;
257280 onChange : ( value : SortById ) => void ;
258281} ) {
259- const values : SortById [ ] = [ "name" , "createdAt" , "totalConnections " ] ;
282+ const values : SortById [ ] = [ "name" , "createdAt" , "monthlyActiveUsers " ] ;
260283 const valueToLabel : Record < SortById , string > = {
261284 name : "Name" ,
262285 createdAt : "Creation Date" ,
263- totalConnections : "Total Users" ,
286+ monthlyActiveUsers : "Monthly Active Users" ,
264287 } ;
265288
266289 return (
0 commit comments