Skip to content

Commit ace1dc5

Browse files
committed
[TOOL-3124] Dashboard: paginate projects, sort by Montly active users (#6027)
<!-- start pr-codex --> ## PR-Codex overview This PR focuses on enhancing the project analytics in the dashboard by changing how project data is retrieved and displayed. It updates the calculation of user connections to reflect monthly active users and introduces pagination for project listings. ### Detailed summary - Replaced `getProjectsWithTotalWallets` with `getProjectsWithAnalytics`. - Updated project data structure to include `monthlyActiveUsers` instead of `totalConnections`. - Introduced pagination in the `TeamProjectsPage` component. - Changed sorting criteria from `totalConnections` to `monthlyActiveUsers`. - Updated UI elements to reflect the new data fields. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent 9f79277 commit ace1dc5

File tree

2 files changed

+55
-23
lines changed

2 files changed

+55
-23
lines changed

apps/dashboard/src/app/team/[team_slug]/(team)/page.tsx

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ import { getWalletConnections } from "@/api/analytics";
22
import { type Project, getProjects } from "@/api/projects";
33
import { getTeamBySlug } from "@/api/team";
44
import { Changelog } from "components/dashboard/Changelog";
5+
import { subDays } from "date-fns";
56
import { redirect } from "next/navigation";
6-
import { TeamProjectsPage } from "./~/projects/TeamProjectsPage";
7+
import {
8+
type ProjectWithAnalytics,
9+
TeamProjectsPage,
10+
} from "./~/projects/TeamProjectsPage";
711

812
export default async function Page(props: {
913
params: Promise<{ team_slug: string }>;
@@ -16,7 +20,7 @@ export default async function Page(props: {
1620
}
1721

1822
const projects = await getProjects(params.team_slug);
19-
const projectsWithTotalWallets = await getProjectsWithTotalWallets(projects);
23+
const projectsWithTotalWallets = await getProjectsWithAnalytics(projects);
2024

2125
return (
2226
<div className="container flex grow flex-col gap-12 py-8 lg:flex-row">
@@ -34,30 +38,35 @@ export default async function Page(props: {
3438
);
3539
}
3640

37-
async function getProjectsWithTotalWallets(
41+
async function getProjectsWithAnalytics(
3842
projects: Project[],
39-
): Promise<Array<Project & { totalConnections: number }>> {
43+
): Promise<Array<ProjectWithAnalytics>> {
4044
return Promise.all(
4145
projects.map(async (p) => {
4246
try {
47+
const today = new Date();
48+
const thirtyDaysAgo = subDays(today, 30);
49+
4350
const data = await getWalletConnections({
4451
clientId: p.publishableKey,
4552
period: "all",
53+
from: thirtyDaysAgo,
54+
to: today,
4655
});
4756

48-
let totalConnections = 0;
57+
let uniqueWalletsConnected = 0;
4958
for (const d of data) {
50-
totalConnections += d.totalConnections;
59+
uniqueWalletsConnected += d.uniqueWalletsConnected;
5160
}
5261

5362
return {
5463
...p,
55-
totalConnections,
64+
monthlyActiveUsers: uniqueWalletsConnected,
5665
};
5766
} catch {
5867
return {
5968
...p,
60-
totalConnections: 0,
69+
monthlyActiveUsers: 0,
6170
};
6271
}
6372
}),

apps/dashboard/src/app/team/[team_slug]/(team)/~/projects/TeamProjectsPage.tsx

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import type { Project } from "@/api/projects";
44
import type { Team } from "@/api/team";
55
import { ProjectAvatar } from "@/components/blocks/Avatars/ProjectAvatar";
6+
import { PaginationButtons } from "@/components/pagination-buttons";
67
import { CopyTextButton } from "@/components/ui/CopyTextButton";
78
import { Button } from "@/components/ui/button";
89
import {
@@ -33,22 +34,24 @@ import {
3334
import Link from "next/link";
3435
import { 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

4043
export 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

150173
function 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

Comments
 (0)