feat(admin): centralize subscriptions under /admin?tab=subscriptions

Replaced the dedicated /admin/subscriptions page with a redirect to the central admin panel’s subscriptions tab. Removed session checks, imports, and the AdminSubscriptionDashboard since routing and access are now handled centrally. This streamlines admin UX and keeps access control unified.
This commit is contained in:
Evandro Fonseca Junior committed 2025-11-09 01:50:50 -03:00
1 parent d8e7d5d7e6
commit 62ab5b2608
19 files changed
+3091 -357

No files matched your search

+16 -16
View File
@@ -1,24 +1,24 @@
import { NextRequest } from "next/server";
import path from "node:path";
function getDb() {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Database = require("better-sqlite3");
const dbPath = path.join(process.cwd(), "data", "tibiawiki.db");
return new Database(dbPath, { readonly: true, fileMustExist: true });
}
import { prisma } from "@/lib/prisma/app";
export async function GET(_req: NextRequest) {
try {
const db = getDb();
const tables = db
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence' ORDER BY name")
.all() as { name: string }[];
db.close();
// Retorna nomes das tabelas (PT) para usar como categorias
return Response.json({ categories: tables.map((t) => t.name) });
const categories = await prisma.item.findMany({
distinct: ["category"],
select: { category: true },
orderBy: { category: "asc" },
});
return Response.json({
categories: categories
.map((row) => row.category)
.filter((category): category is string => Boolean(category)),
});
} catch (e: any) {
return Response.json({ error: e?.message || "Erro" }, { status: 500 });
return Response.json(
{ error: e?.message || "Erro" },
{ status: 500 }
);
}
}
+30 -24
View File
@@ -1,60 +1,66 @@
import { NextRequest } from "next/server";
import { searchItems } from "@/lib/items-db";
import { searchItems, type ItemSort } from "@/lib/prisma/queries/items";
import { buildPublicItemImageUrl } from "@/lib/item-images";
function parseArray(param: string | null): string[] {
if (!param) return [];
// Suporta formatos: comma-separated (a,b) ou múltiplos parâmetros já combinados
return param
.split(",")
.map((v) => v.trim())
.map((value) => value.trim())
.filter(Boolean);
}
const allowedSorts: ItemSort[] = [
"name",
"level-asc",
"level-desc",
"weight-asc",
"weight-desc",
"category",
"updated-desc",
];
export async function GET(req: NextRequest) {
try {
const { searchParams } = new URL(req.url);
const q = searchParams.get("q") || undefined;
const categories = parseArray(searchParams.get("category"));
const rarities = parseArray(searchParams.get("rarity"));
const sortParam = (searchParams.get("sort") || "name") as
| "name"
| "level-asc"
| "level-desc"
| "weight-asc"
| "weight-desc"
| "category";
const server = searchParams.get("server") || undefined;
const sortParamRaw = (searchParams.get("sort") || "name").toLowerCase();
const sortParam = (allowedSorts.find((sort) => sort === sortParamRaw) || "name") as ItemSort;
const page = Number(searchParams.get("page") || "1");
const pageSize = Number(searchParams.get("pageSize") || "24");
const voc = searchParams.get("voc") || undefined;
const { items, total } = searchItems({
const { items, total } = await searchItems({
q,
categories,
rarities,
category: categories[0],
rarity: rarities[0],
server,
sort: sortParam,
vocation: voc,
page,
pageSize,
});
// Enriquecer com URL pública de imagem quando possível
const itemsWithImage = items.map((it: any) => {
const img = (it.image || "").toString();
// Preferir URL absoluta do banco para teste
const itemsWithImage = items.map((item) => {
const img = (item.image_url || item.image_local_path || "").toString();
if (/^https?:\/\//i.test(img)) {
return { ...it, image: img };
return { ...item, image_url: img, image: img };
}
if (img.startsWith("data/")) {
return { ...it, image: `/api/images?path=${encodeURIComponent(img)}` };
return { ...item, image_url: img, image: `/api/images?path=${encodeURIComponent(img)}` };
}
const categoryEn = (it.category || "other").toString();
return { ...it, image: buildPublicItemImageUrl(categoryEn, img) };
const category = item.category || "other";
return {
...item,
image_url: item.image_url,
image: buildPublicItemImageUrl(category, img),
};
});
const totalPages = Math.max(1, Math.ceil(total / Math.max(1, pageSize)));
return Response.json(
{ items: itemsWithImage, page, pageSize, total, totalPages },
{ items: itemsWithImage, page, pageSize, total, totalPages, sort: sortParam },
{ status: 200 }
);
} catch (error: any) {