import { asc, count, desc } from "drizzle-orm"; import { ShoppingCart } from "lucide-react"; import Link from "next/link"; import { redirect } from "next/navigation"; import { getTranslations } from "next-intl/server"; import { AdminPageShell } from "@/components/admin/admin-page-shell"; import { AdminSimplePager } from "@/components/admin/admin-simple-pager"; import { StatusCard } from "@/components/admin/dashboard"; import { CurrencyIcon } from "@/components/shared/currency-icon"; import { Button } from "@/components/ui/button"; import { calcPagination, parseListParams } from "@/lib/admin-helpers"; import { db, WebsitePaypalTransactions, WebsiteShopArticles } from "@/lib/db"; import { formatDate } from "@/lib/format-date"; import { canAccess, getAdminContext, PERMS } from "@/lib/permissions"; const PAID_STATUS = new Set(["completed", "paid", "success", "approved"]); const RECENT_ORDERS = 25; function statusState( status: string | null | undefined, ): "ok" | "danger" | undefined { if (!status) return undefined; const s = status.toLowerCase(); if (PAID_STATUS.has(s)) return "ok"; if ( s === "failed" || s === "denied" || s === "refunded" || s === "cancelled" || s === "canceled" ) return "danger"; return undefined; } function CurrencyCell({ kind, value, }: { kind: "credits" | "duckets" | "diamonds"; value: number | null | undefined; }) { if (value == null) { return โ€”; } return ( {value} ); } export default async function AdminShop({ searchParams, }: { searchParams: Promise>; }) { const { session, permissions } = await getAdminContext(); if (!canAccess(permissions, PERMS.SHOP_VIEW, session.user.rank)) { redirect("/admin"); } const t = await getTranslations("pages.admin.shop"); const raw = await searchParams; const parsed = parseListParams(new URLSearchParams(raw)); let packageTotal = 0; let packages: (typeof WebsiteShopArticles.$inferSelect)[] = []; let loadError = false; try { const [totalRow] = await db .select({ total: count() }) .from(WebsiteShopArticles); packageTotal = Number(totalRow?.total ?? 0); const pagination = calcPagination( packageTotal, parsed.page, parsed.perPage, ); packages = await db .select() .from(WebsiteShopArticles) .orderBy(asc(WebsiteShopArticles.position), asc(WebsiteShopArticles.name)) .limit(pagination.perPage) .offset(pagination.offset); } catch { packages = []; packageTotal = 0; loadError = true; } const pkgPagination = calcPagination( packageTotal, parsed.page, parsed.perPage, ); let orders: (typeof WebsitePaypalTransactions.$inferSelect)[] = []; try { orders = await db .select() .from(WebsitePaypalTransactions) .orderBy(desc(WebsitePaypalTransactions.createdAt)) .limit(RECENT_ORDERS); } catch { orders = []; loadError = true; } const paidOrders = orders.filter( (o) => statusState(o.status) === "ok", ).length; return ( {t("newPackage")} } >
{loadError ? (
Could not load some shop data (database unavailable).
) : null}
0 ? "ok" : "neutral"} icon="๐Ÿ’ณ" />

{t("packagesTotal", { count: packageTotal })}

{packages.length === 0 ? (
{t("noPackages")}
) : (
{packages.map((p) => ( ))}
# {t("colName")} {t("colPrice")} {t("colCredits")} {t("colDuckets")} {t("colDiamonds")} {t("colRank")} {t("colPosition")}
{String(p.id)} {p.name} {p.costs} {p.giveRank ?? "โ€”"} {p.position}
)}

{t("recentOrders")} ({orders.length})

{t("ordersHint")}

{orders.length === 0 ? (
{t("noOrders")}
) : (
{orders.map((o) => { const state = statusState(o.status); return ( ); })}
{t("colTransaction")} {t("colUser")} {t("colDescription")} {t("colAmount")} {t("colStatus")} {t("colDate")}
{o.transactionId} #{o.userId} {o.description ?? "โ€”"} {o.amount} {o.currency} {o.status ? ( {o.status} ) : ( โ€” )} {formatDate(o.createdAt, "date")}
)}
); }