Skip to content

Commit e35dbfd

Browse files
committed
[TOOL-3124] Dashboard: Show 8 top projects, Add show more button for full list
1 parent 9f79277 commit e35dbfd

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)