feat(support): filter waiting tickets and staff assignments
CI / check (push) Failing after 53s
CI / deploy (push) Skipped
CI / publish-container (push) Skipped

This commit is contained in:
Simo committed 2026-09-11 00:20:54 +02:00
1 parent 5d18af932d
commit 25d0a13050
7 files changed
+173 -6

No files matched your search

+25 -3
View File
@@ -19,7 +19,14 @@ import {
import { StatusCard } from "@/components/admin/dashboard";
import { TicketQueueBanner } from "@/components/admin/ticket-queue-banner";
import { requireModPermission } from "@/lib/admin/guard";
import {
awaitingStaffCondition,
latestTicketReplyAt,
latestTicketReplyIsStaff,
ticketAssignmentCondition,
} from "@/lib/admin/ticket-desk-query";
import { fetchTicketQueueOpenCounts } from "@/lib/admin/ticket-queue-counts";
import { ticketReplyAge } from "@/lib/admin/ticket-reply-age";
import { calcPagination, parseListParams } from "@/lib/admin-helpers";
import { db, User, WebsiteTicket, WebsiteTicketMessage } from "@/lib/db";
import { formatDate } from "@/lib/format-date";
@@ -42,7 +49,10 @@ export default async function ModTicketsDeskPage({
}: {
searchParams: Promise<Record<string, string>>;
}) {
await requireModPermission([PERMS.MOD_TICKETS_VIEW, PERMS.TICKETS_VIEW]);
const staff = await requireModPermission([
PERMS.MOD_TICKETS_VIEW,
PERMS.TICKETS_VIEW,
]);
const t = await getTranslations("pages.admin.tickets");
const raw = await searchParams;
@@ -50,8 +60,12 @@ export default async function ModTicketsDeskPage({
const statusFilter = raw.filter_status || raw.status || "active";
const conditions: SQL[] = [];
const assignment = ticketAssignmentCondition(raw.filter_assignee, staff.id);
if (assignment) conditions.push(assignment);
if (statusFilter === "active") {
if (statusFilter === "awaiting_staff") {
if (awaitingStaffCondition) conditions.push(awaitingStaffCondition);
} else if (statusFilter === "active") {
conditions.push(ne(WebsiteTicket.status, "closed"));
} else if (statusFilter && statusFilter !== "all") {
conditions.push(eq(WebsiteTicket.status, statusFilter));
@@ -137,6 +151,8 @@ export default async function ModTicketsDeskPage({
createdAt: WebsiteTicket.createdAt,
creatorUsername: Creator.username,
assigneeUsername: Assignee.username,
replyAt: latestTicketReplyAt,
replyIsStaff: latestTicketReplyIsStaff,
})
.from(WebsiteTicket)
.leftJoin(Creator, eq(WebsiteTicket.creatorId, Creator.id))
@@ -170,6 +186,9 @@ export default async function ModTicketsDeskPage({
category: ticket.category,
messages: msgMap.get(ticket.id) ?? 0,
status: ticket.status,
awaitingStaff:
ticket.status !== "closed" && Number(ticket.replyIsStaff) === 0,
replyAgeMinutes: ticketReplyAge(ticket.replyAt),
priority: ticket.priority,
assignee: ticket.assigneeUsername ?? "—",
date: formatDate(ticket.createdAt, "date"),
@@ -203,7 +222,10 @@ export default async function ModTicketsDeskPage({
<StatusCard label={t("statusClosed")} value={closedCount} icon="✅" />
</div>
{total === 0 && !parsed.search && statusFilter === "active" ? (
{total === 0 &&
!parsed.search &&
statusFilter === "active" &&
!raw.filter_assignee ? (
<div className="admin-empty">{t("noTickets")}</div>
) : (
<TicketsTable