52 lines
2 KiB
TypeScript
52 lines
2 KiB
TypeScript
import { Badge, EmptyState } from '@/components/ui';
|
|
import { UserActions } from '@/components/admin/UserActions';
|
|
import { requireAdmin } from '@/lib/server/auth';
|
|
import { db } from '@/lib/server/db';
|
|
import { formatDate } from '@/lib/utils';
|
|
import { t } from '@/lib/i18n';
|
|
|
|
export const dynamic = 'force-dynamic';
|
|
|
|
export default async function AdminUsersPage() {
|
|
await requireAdmin();
|
|
const users = await db.user.findMany({ orderBy: { createdAt: 'asc' }, include: { subscription: true } });
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<h1 className="text-2xl font-bold">{t('admin.users')}</h1>
|
|
{users.length === 0 ? (
|
|
<EmptyState />
|
|
) : (
|
|
<div className="overflow-x-auto rounded-xl border" style={{ borderColor: 'var(--border)' }}>
|
|
<table className="w-full text-sm">
|
|
<thead className="muted text-left text-xs uppercase">
|
|
<tr>
|
|
<th className="px-4 py-3">Email</th>
|
|
<th className="px-4 py-3">Role</th>
|
|
<th className="px-4 py-3">Plan</th>
|
|
<th className="px-4 py-3">Created</th>
|
|
<th className="px-4 py-3 text-right">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{users.map((u) => (
|
|
<tr key={u.id} className="border-t" style={{ borderColor: 'var(--border)' }}>
|
|
<td className="px-4 py-3 font-medium">{u.email}</td>
|
|
<td className="px-4 py-3">
|
|
<Badge tone={u.role === 'admin' ? 'brand' : 'neutral'}>{u.role}</Badge>
|
|
</td>
|
|
<td className="px-4 py-3">{u.subscription?.plan ?? 'free'}</td>
|
|
<td className="px-4 py-3">{formatDate(u.createdAt)}</td>
|
|
<td className="px-4 py-3">
|
|
<UserActions id={u.id} role={u.role} />
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|