feat(admin): P1 — clearer tickets labels, pagination, min_staff_rank, analytics errors
Deploy / release (push) Skipped
Deploy / deploy (push) Successful in 1m37s

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
SimoandCursor committed 2026-07-22 19:04:45 +02:00
1 parent 75cdfdebe4
commit f150aea8b9
13 files changed
+311 -101

No files matched your search

+19 -8
View File
@@ -1,9 +1,9 @@
import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { StatusCard } from "@/components/admin/dashboard";
import { prisma } from "@/lib/prisma";
import { redirect } from "next/navigation";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
import { prisma } from "@/lib/prisma";
export const dynamic = "force-dynamic";
@@ -31,6 +31,7 @@ export default async function AdminCalendar() {
const t = await getTranslations("pages.admin.calendar");
let campaigns: Campaign[] = [];
let loadError = false;
try {
campaigns = await prisma.calendarCampaigns.findMany({
select: {
@@ -43,27 +44,37 @@ export default async function AdminCalendar() {
enabled: true,
},
orderBy: { id: "desc" },
take: 200,
});
} catch {
campaigns = [];
loadError = true;
}
const rewardCounts = new Map<number, number>();
let totalRewards = 0;
try {
const rewards = await prisma.calendarRewards.findMany({
select: { campaignId: true },
const grouped = await prisma.calendarRewards.groupBy({
by: ["campaignId"],
_count: { _all: true },
});
totalRewards = rewards.length;
for (const r of rewards) {
rewardCounts.set(r.campaignId, (rewardCounts.get(r.campaignId) ?? 0) + 1);
for (const g of grouped) {
rewardCounts.set(g.campaignId, g._count._all);
totalRewards += g._count._all;
}
} catch {}
} catch {
loadError = true;
}
const enabledCount = campaigns.filter((c) => c.enabled === "1").length;
return (
<main>
{loadError ? (
<div className="mb-4 rounded-lg bg-[var(--admin-error-subtle)] p-3 text-xs text-[var(--admin-error)]">
Could not load some calendar data (database unavailable).
</div>
) : null}
<div className="grid grid-cols-[repeat(auto-fit,minmax(180px,1fr))] gap-3.5 mb-6">
<StatusCard label={t("campaigns")} value={campaigns.length} icon="📅" />
<StatusCard