templates2.Base.Next/app/admin/users/page.tsx
w4c-templates 219be916cb
Some checks are pending
CI / quality (push) Waiting to run
chore(template): publish Base.Next
2026-10-11 23:23:30 +03:00

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>
);
}