diff --git a/apps/web/src/app/(dashboard)/admin/documents/data-table.tsx b/apps/web/src/app/(dashboard)/admin/documents/data-table.tsx
index b1ab92e42..1d121742a 100644
--- a/apps/web/src/app/(dashboard)/admin/documents/data-table.tsx
+++ b/apps/web/src/app/(dashboard)/admin/documents/data-table.tsx
@@ -10,10 +10,10 @@ import { useSession } from 'next-auth/react';
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
import { FindResultSet } from '@documenso/lib/types/find-result-set';
import { Document, Recipient, User } from '@documenso/prisma/client';
+import { Avatar, AvatarFallback } from '@documenso/ui/primitives/avatar';
import { DataTable } from '@documenso/ui/primitives/data-table';
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
-import { StackAvatarsWithTooltip } from '~/components/(dashboard)/avatar/stack-avatars-with-tooltip';
import { DocumentStatus } from '~/components/formatter/document-status';
import { LocaleDate } from '~/components/formatter/locale-date';
@@ -68,15 +68,11 @@ export const DocumentsDataTable = ({ results }: DocumentsDataTableProps) => {
cell: ({ row }) => {
return (
-
+
+
+ {row.original.User.name}
+
+
);
},
diff --git a/apps/web/src/app/(dashboard)/admin/documents/page.tsx b/apps/web/src/app/(dashboard)/admin/documents/page.tsx
index d62d82ada..6b5a0761c 100644
--- a/apps/web/src/app/(dashboard)/admin/documents/page.tsx
+++ b/apps/web/src/app/(dashboard)/admin/documents/page.tsx
@@ -11,12 +11,10 @@ export type DocumentsPageProps = {
};
export default async function Documents({ searchParams = {} }: DocumentsPageProps) {
- const user = await getRequiredServerComponentSession();
const page = Number(searchParams.page) || 1;
const perPage = Number(searchParams.perPage) || 20;
const results = await findDocuments({
- userId: user.id,
orderBy: {
column: 'createdAt',
direction: 'desc',
diff --git a/apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx b/apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx
index 0329b6a17..a598fc605 100644
--- a/apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx
+++ b/apps/web/src/app/(dashboard)/admin/users/data-table-users.tsx
@@ -7,7 +7,7 @@ import Link from 'next/link';
import { Edit, Loader } from 'lucide-react';
import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
-import { Role } from '@documenso/prisma/client';
+import { Document, Role, Subscription } from '@documenso/prisma/client';
import { Button } from '@documenso/ui/primitives/button';
import { DataTable } from '@documenso/ui/primitives/data-table';
import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
@@ -17,18 +17,16 @@ interface User {
name: string | null;
email: string;
roles: Role[];
- Subscription: Subscription[];
- Document: Document[];
+ Subscription: SubscriptionLite[];
+ Document: DocumentLite[];
}
-interface Subscription {
- id: number;
- status: string;
- planId: string | null;
- priceId: string | null;
- createdAt: Date | null;
- periodEnd: Date | null;
-}
+type SubscriptionLite = Pick<
+ Subscription,
+ 'id' | 'status' | 'planId' | 'priceId' | 'createdAt' | 'periodEnd'
+>;
+
+type DocumentLite = Pick;
type UsersDataTableProps = {
users: User[];
@@ -37,10 +35,6 @@ type UsersDataTableProps = {
totalPages: number;
};
-type Document = {
- id: number;
-};
-
export const UsersDataTable = ({ users, perPage, page, totalPages }: UsersDataTableProps) => {
const [isPending, startTransition] = useTransition();
const updateSearchParams = useUpdateSearchParams();
@@ -97,7 +91,7 @@ export const UsersDataTable = ({ users, perPage, page, totalPages }: UsersDataTa
if (row.original.Subscription && row.original.Subscription.length > 0) {
return (
<>
- {row.original.Subscription.map((subscription: Subscription, i: number) => {
+ {row.original.Subscription.map((subscription: SubscriptionLite, i: number) => {
return {subscription.status};
})}
>
diff --git a/apps/web/src/app/(dashboard)/admin/users/page.tsx b/apps/web/src/app/(dashboard)/admin/users/page.tsx
index 7f8b9af47..67dc5563b 100644
--- a/apps/web/src/app/(dashboard)/admin/users/page.tsx
+++ b/apps/web/src/app/(dashboard)/admin/users/page.tsx
@@ -1,10 +1,6 @@
import { findUsers } from '@documenso/lib/server-only/user/get-all-users';
-/*
-1. retrieve all users from the db
-2. display them in a table
-*/
-import { UsersDataTable } from './data-table-users';
+import { Users } from './users';
type AdminManageUsersProps = {
searchParams?: {
@@ -13,23 +9,22 @@ type AdminManageUsersProps = {
};
};
-export default async function AdminManageUsers({ searchParams = {} }: AdminManageUsersProps) {
+export default function AdminManageUsers({ searchParams = {} }: AdminManageUsersProps) {
const page = Number(searchParams.page) || 1;
const perPage = Number(searchParams.perPage) || 10;
- const results = await findUsers({ page, perPage });
+ async function search(search: string) {
+ 'use server';
+
+ const results = await findUsers({ username: search, email: search, page, perPage });
+
+ return results;
+ }
return (
);
}
diff --git a/apps/web/src/app/(dashboard)/admin/users/users.tsx b/apps/web/src/app/(dashboard)/admin/users/users.tsx
new file mode 100644
index 000000000..e44772dbb
--- /dev/null
+++ b/apps/web/src/app/(dashboard)/admin/users/users.tsx
@@ -0,0 +1,78 @@
+'use client';
+
+import { useEffect, useState } from 'react';
+
+import { Document, Role, Subscription } from '@documenso/prisma/client';
+import { Button } from '@documenso/ui/primitives/button';
+import { Input } from '@documenso/ui/primitives/input';
+
+import { UsersDataTable } from './data-table-users';
+
+export type SubscriptionLite = Pick<
+ Subscription,
+ 'id' | 'status' | 'planId' | 'priceId' | 'createdAt' | 'periodEnd'
+>;
+export type DocumentLite = Pick;
+
+export type User = {
+ id: number;
+ name: string | null;
+ email: string;
+ roles: Role[];
+ Subscription: SubscriptionLite[];
+ Document: DocumentLite[];
+};
+
+export type UsersProps = {
+ search: (search: string) => Promise<{ users: User[]; totalPages: number }>;
+ perPage: number;
+ page: number;
+};
+
+export const Users = ({ search, perPage, page }: UsersProps) => {
+ const [data, setData] = useState([]);
+ const [totalPages, setTotalPages] = useState(0);
+
+ const [searchString, setSearchString] = useState('');
+
+ useEffect(() => {
+ const fetchData = async () => {
+ try {
+ const result = await search(searchString);
+ setData(result.users);
+ setTotalPages(result.totalPages);
+ } catch (err) {
+ throw new Error(err);
+ }
+ };
+
+ fetchData();
+ }, [searchString, search]);
+
+ const onSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+ const result = await search(searchString);
+ setData(result.users);
+ };
+
+ const handleChange = (e: React.ChangeEvent) => {
+ setSearchString(e.target.value);
+ };
+
+ return (
+ <>
+
+
+
+
+ >
+ );
+};
diff --git a/apps/web/src/components/(dashboard)/admin/generic-data-table.tsx b/apps/web/src/components/(dashboard)/admin/generic-data-table.tsx
new file mode 100644
index 000000000..1dd3e01d3
--- /dev/null
+++ b/apps/web/src/components/(dashboard)/admin/generic-data-table.tsx
@@ -0,0 +1,57 @@
+import { useTransition } from 'react';
+
+import { ColumnDef } from '@tanstack/react-table';
+import { Loader } from 'lucide-react';
+
+import { useUpdateSearchParams } from '@documenso/lib/client-only/hooks/use-update-search-params';
+import { DataTable } from '@documenso/ui/primitives/data-table';
+import { DataTablePagination } from '@documenso/ui/primitives/data-table-pagination';
+
+type GenericDataTableProps = {
+ columns: ColumnDef[];
+ data: TData[];
+ perPage: number;
+ currentPage: number;
+ totalPages: number;
+};
+
+export function GenericDataTable({
+ columns,
+ data,
+ perPage,
+ currentPage,
+ totalPages,
+}: GenericDataTableProps) {
+ const [isPending, startTransition] = useTransition();
+ const updateSearchParams = useUpdateSearchParams();
+
+ const onPaginationChange = (page: number, perPage: number) => {
+ startTransition(() => {
+ updateSearchParams({
+ page: page.toString(),
+ perPage: perPage.toString(),
+ });
+ });
+ };
+
+ return (
+
+
+ {(table) => }
+
+
+ {isPending && (
+
+
+
+ )}
+
+ );
+}
diff --git a/packages/lib/server-only/user/get-all-users.ts b/packages/lib/server-only/user/get-all-users.ts
index 35e165260..babcc7ba1 100644
--- a/packages/lib/server-only/user/get-all-users.ts
+++ b/packages/lib/server-only/user/get-all-users.ts
@@ -1,11 +1,37 @@
+import { Prisma } from '@prisma/client';
+
import { prisma } from '@documenso/prisma';
type getAllUsersProps = {
+ username: string;
+ email: string;
page: number;
perPage: number;
};
-export const findUsers = async ({ page = 1, perPage = 10 }: getAllUsersProps) => {
+export const findUsers = async ({
+ username = '',
+ email = '',
+ page = 1,
+ perPage = 10,
+}: getAllUsersProps) => {
+ const whereClause = Prisma.validator()({
+ OR: [
+ {
+ name: {
+ contains: username,
+ mode: 'insensitive',
+ },
+ },
+ {
+ email: {
+ contains: email,
+ mode: 'insensitive',
+ },
+ },
+ ],
+ });
+
const [users, count] = await Promise.all([
await prisma.user.findMany({
select: {
@@ -29,10 +55,13 @@ export const findUsers = async ({ page = 1, perPage = 10 }: getAllUsersProps) =>
},
},
},
+ where: whereClause,
skip: Math.max(page - 1, 0) * perPage,
take: perPage,
}),
- await prisma.user.count(),
+ await prisma.user.count({
+ where: whereClause,
+ }),
]);
return {