fix(admin): live online widget, ticket queue clarity, i18n+contract coverage
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
9177230dc2
commit
01126207dc
26 files changed
+1635
-114
No files matched your search
@@ -53,6 +53,7 @@ export default async function CommandoCentrum() {
|
||||
emulatorOnline,
|
||||
maintenance,
|
||||
activity,
|
||||
onlineUsersRaw,
|
||||
] = await Promise.all([
|
||||
prisma.user.count({ where: { online: "1" } }).catch(() => 0),
|
||||
prisma.user.count().catch(() => -1),
|
||||
@@ -70,8 +71,30 @@ export default async function CommandoCentrum() {
|
||||
.catch(
|
||||
() => [] as Awaited<ReturnType<typeof prisma.staffActivities.findMany>>,
|
||||
),
|
||||
prisma.user
|
||||
.findMany({
|
||||
where: { online: "1" },
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
look: true,
|
||||
lastOnline: true,
|
||||
},
|
||||
orderBy: { lastOnline: "desc" },
|
||||
take: 40,
|
||||
})
|
||||
.catch(() => []),
|
||||
]);
|
||||
|
||||
const onlineUsers = onlineUsersRaw.map((u) => ({
|
||||
id: u.id,
|
||||
username: u.username,
|
||||
look: u.look,
|
||||
roomId: null as number | null,
|
||||
roomName: null as string | null,
|
||||
lastActivity: u.lastOnline > 0 ? new Date(u.lastOnline * 1000) : new Date(),
|
||||
}));
|
||||
|
||||
const staffIds = Array.from(
|
||||
new Set(activity.map((a) => Number(a.userId))),
|
||||
).filter((n) => n > 0);
|
||||
@@ -134,7 +157,7 @@ export default async function CommandoCentrum() {
|
||||
{/* ── Online users widget ───────────────────────────────── */}
|
||||
<section className="admin-card mb-6">
|
||||
<h2 className="admin-section-title">{t("onlineUsers")}</h2>
|
||||
<OnlineUsersWidget users={[]} isLoading={false} />
|
||||
<OnlineUsersWidget users={onlineUsers} isLoading={false} />
|
||||
</section>
|
||||
|
||||
{/* ── Server info + diagnostics ──────────────────────────── */}
|
||||
|
||||
@@ -160,6 +160,20 @@ export default async function AdminHelpTicketsPage({
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div
|
||||
className="rounded-lg border border-[var(--admin-info-border)] bg-[var(--admin-info-subtle)] px-4 py-3 text-sm"
|
||||
role="status"
|
||||
>
|
||||
<p className="m-0">{t("queueHint")}</p>
|
||||
<p className="m-0 mt-1">
|
||||
<a
|
||||
href="/admin/tickets"
|
||||
className="font-medium text-[var(--admin-accent)] underline-offset-2 hover:underline"
|
||||
>
|
||||
{t("queueOtherCta")}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(180px,1fr))] gap-3.5">
|
||||
<StatusCard label={t("statusOpen")} value={openCount} icon="🎫" />
|
||||
<StatusCard label={t("statusClosed")} value={closedCount} icon="✅" />
|
||||
|
||||
@@ -116,6 +116,20 @@ export default async function AdminTicketsPage({
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div
|
||||
className="rounded-lg border border-[var(--admin-info-border)] bg-[var(--admin-info-subtle)] px-4 py-3 text-sm"
|
||||
role="status"
|
||||
>
|
||||
<p className="m-0">{t("queueHint")}</p>
|
||||
<p className="m-0 mt-1">
|
||||
<a
|
||||
href="/admin/help-tickets"
|
||||
className="font-medium text-[var(--admin-accent)] underline-offset-2 hover:underline"
|
||||
>
|
||||
{t("queueOtherCta")}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(180px,1fr))] gap-3.5">
|
||||
<StatusCard label={t("statusOpen")} value={openCount} icon="🎫" />
|
||||
<StatusCard
|
||||
|
||||
Reference in new issue
Block a user