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

@@ -0,0 +1,50 @@
import { NextRequest, NextResponse } from "next/server";
import { requireAdminUser } from "@/lib/auth/middleware";
import { addColumnToCategory, type SQLiteColumnDefinition } from "@/lib/items/sqlite-manager";
import { secureLogger } from "@/lib/secure-logger";
function sanitizeColumn(column: any): SQLiteColumnDefinition {
const name = typeof column?.name === "string" ? column.name.trim().toLowerCase() : "";
const type = typeof column?.type === "string" ? column.type : "TEXT";
const notNull = column?.notNull === true;
const defaultValue = column?.defaultValue ?? undefined;
if (!name) {
throw new Error("Nome da coluna é obrigatório");
}
if (["id", "nome", "image_url", "image_local_path"].includes(name)) {
throw new Error("Coluna reservada não pode ser criada");
}
return {
name,
type: type.toUpperCase(),
notNull,
defaultValue,
editable: column?.editable !== false,
} satisfies SQLiteColumnDefinition;
}
export async function POST(request: NextRequest, { params }: { params: Promise<{ name: string }> }) {
const auth = await requireAdminUser(request);
if (auth instanceof NextResponse) {
return auth;
}
const { name } = await params;
try {
const body = await request.json();
const column = sanitizeColumn(body?.column ?? body);
const created = addColumnToCategory({ category: name, column });
return NextResponse.json({ success: true, column: created }, { status: 201 });
} catch (error) {
secureLogger.error("Falha ao adicionar coluna à categoria", error);
return NextResponse.json(
{ success: false, error: error instanceof Error ? error.message : "Erro ao adicionar coluna" },
{ status: 400 },
);
}
}
+83
View File
@@ -0,0 +1,83 @@
import { NextRequest, NextResponse } from "next/server";
import { requireAdminUser } from "@/lib/auth/middleware";
import {
listCategoryTemplates,
createCategoryTemplate,
type SQLiteColumnDefinition,
type CreateCategoryInput,
} from "@/lib/items/sqlite-manager";
import { secureLogger } from "@/lib/secure-logger";
export async function GET(request: NextRequest) {
const auth = await requireAdminUser(request);
if (auth instanceof NextResponse) {
return auth;
}
try {
const templates = listCategoryTemplates();
return NextResponse.json({ success: true, categories: templates }, { status: 200 });
} catch (error) {
secureLogger.error("Falha ao listar categorias dinâmicas", error);
return NextResponse.json(
{ success: false, error: "Não foi possível listar categorias" },
{ status: 500 },
);
}
}
function sanitizeColumn(column: any): SQLiteColumnDefinition {
const name = typeof column?.name === "string" ? column.name.trim().toLowerCase() : "";
const type = typeof column?.type === "string" ? column.type : "TEXT";
const notNull = column?.notNull === true;
const defaultValue = column?.defaultValue ?? undefined;
if (!name) {
throw new Error("Nome da coluna é obrigatório");
}
return {
name,
type: type.toUpperCase(),
notNull,
defaultValue,
editable: column?.editable !== false,
} satisfies SQLiteColumnDefinition;
}
export async function POST(request: NextRequest) {
const auth = await requireAdminUser(request);
if (auth instanceof NextResponse) {
return auth;
}
try {
const body = await request.json();
const rawName = typeof body?.name === "string" ? body.name.trim().toLowerCase() : "";
if (!rawName) {
return NextResponse.json(
{ success: false, error: "Nome da categoria é obrigatório" },
{ status: 400 },
);
}
const columnsArray: unknown[] = Array.isArray(body?.columns) ? body.columns : [];
const columns = columnsArray.map((column) => sanitizeColumn(column)).filter((column) => {
return !(column && ["id", "nome", "image_url", "image_local_path"].includes(column.name));
});
const input: CreateCategoryInput = {
name: rawName,
columns,
};
const category = createCategoryTemplate(input);
return NextResponse.json({ success: true, category }, { status: 201 });
} catch (error) {
secureLogger.error("Falha ao criar categoria dinâmica", error);
return NextResponse.json(
{ success: false, error: error instanceof Error ? error.message : "Erro ao criar categoria" },
{ status: 400 },
);
}
}