import { Metadata } from 'next'; import { db } from '@/lib/db'; import { auth } from '@/lib/auth'; import { redirect } from 'next/navigation'; import { getCachedBunnyStorageStats, getCachedUserBunnyStorage, getCachedUserMediaStorage } from '@/lib/admin-stats'; import { Film, HardDrive } from 'lucide-react'; import Link from 'next/link'; import { Button } from '@/components/ui/button'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { format } from 'date-fns'; export const metadata: Metadata = { title: 'Manage Users | Admin', }; function formatBytes(bytes: number, decimals = 2) { if (bytes < 0) return 'Error Fetching'; if (!+bytes) return '0 Bytes'; const k = 1000; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`; } export default async function AdminUsersPage({ searchParams }: { searchParams: { page?: string } }) { const session = await auth(); if (!session?.user?.isAdmin) { redirect('/'); } const page = Number(searchParams?.page) || 1; const pageSize = 20; const skip = (page - 1) * pageSize; // Fetch users with their counts and total count const [users, totalUsers] = await Promise.all([ db.user.findMany({ skip, take: pageSize, orderBy: { createdAt: 'desc' }, select: { id: true, name: true, email: true, createdAt: true, _count: { select: { ownedWorkspaces: true, projects: true, comments: true, } } } }), db.user.count() ]); const totalPages = Math.ceil(totalUsers / pageSize); // Determine per-user storage usage (cached) const [userStorage, userBunnyStorage, bunnyStorageStats] = await Promise.all([ getCachedUserMediaStorage(), getCachedUserBunnyStorage(), getCachedBunnyStorageStats(), ]); return (

Users

Bunny Stream Storage
{formatBytes(bunnyStorageStats.totalBytes)}
Cloudflare R2 Media Storage
{formatBytes(Object.values(userStorage).reduce((sum, item) => sum + item.total, 0))}
All Users A comprehensive list of all {totalUsers} users registered on the platform.
User Joined Date Workspaces Owned Projects Owned Total Comments Bunny Upload Media Storage {users.length === 0 ? ( No users found. ) : ( users.map((user) => (
{user.name || 'Anonymous'} {user.email}
{format(new Date(user.createdAt), 'MMM dd, yyyy')} {user._count.ownedWorkspaces} {user._count.projects} {user._count.comments} {formatBytes(userBunnyStorage[user.id] || 0)}
{formatBytes(userStorage[user.id]?.total || 0)} {(userStorage[user.id]?.voice > 0 || userStorage[user.id]?.image > 0) && ( {userStorage[user.id]?.voice > 0 && 🎤 {formatBytes(userStorage[user.id]?.voice)}} {userStorage[user.id]?.voice > 0 && userStorage[user.id]?.image > 0 && } {userStorage[user.id]?.image > 0 && 🖼️ {formatBytes(userStorage[user.id]?.image)}} )}
)) )}
{/* Pagination */} {totalPages > 1 && (
Page {page} of {totalPages}
)}
); }