feat: CSV exports, PDF improvements, play internal/external with hour split, roles cleanup, admin companies with 'Cliente avulso', ticket list spacing/alignment fixes, status translations and mappings

This commit is contained in:
Esdras Renan 2025-10-07 13:42:45 -03:00
parent addd4ce6e8
commit 3bafcc5a0a
45 changed files with 1401 additions and 256 deletions

View file

@ -0,0 +1,27 @@
import { NextResponse } from "next/server"
import { prisma } from "@/lib/prisma"
import { assertAdminSession } from "@/lib/auth-server"
export const runtime = "nodejs"
export async function PATCH(request: Request, { params }: { params: Promise<{ id: string }> }) {
const session = await assertAdminSession()
if (!session) return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
const { id } = await params
const body = await request.json()
const updates: Record<string, any> = {}
for (const key of ["name", "slug", "cnpj", "domain", "phone", "description", "address"]) {
if (key in body) updates[key] = body[key] ?? null
}
if ("isAvulso" in body) updates.isAvulso = Boolean(body.isAvulso)
try {
const company = await prisma.company.update({ where: { id }, data: updates as any })
return NextResponse.json({ company })
} catch (error) {
console.error("Failed to update company", error)
return NextResponse.json({ error: "Falha ao atualizar empresa" }, { status: 500 })
}
}

View file

@ -0,0 +1,47 @@
import { NextResponse } from "next/server"
import { prisma } from "@/lib/prisma"
import { assertAdminSession } from "@/lib/auth-server"
export const runtime = "nodejs"
export async function GET() {
const session = await assertAdminSession()
if (!session) return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
const companies = await prisma.company.findMany({
orderBy: { name: "asc" },
})
return NextResponse.json({ companies })
}
export async function POST(request: Request) {
const session = await assertAdminSession()
if (!session) return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
const body = await request.json()
const { name, slug, isAvulso, cnpj, domain, phone, description, address } = body ?? {}
if (!name || !slug) {
return NextResponse.json({ error: "Nome e slug são obrigatórios" }, { status: 400 })
}
try {
const company = await prisma.company.create({
data: ({
tenantId: session.user.tenantId ?? "tenant-atlas",
name: String(name),
slug: String(slug),
isAvulso: Boolean(isAvulso ?? false),
cnpj: cnpj ? String(cnpj) : null,
domain: domain ? String(domain) : null,
phone: phone ? String(phone) : null,
description: description ? String(description) : null,
address: address ? String(address) : null,
} as any),
})
return NextResponse.json({ company })
} catch (error) {
console.error("Failed to create company", error)
return NextResponse.json({ error: "Falha ao criar empresa" }, { status: 500 })
}
}

View file

@ -0,0 +1,37 @@
import { NextResponse } from "next/server"
import { ConvexHttpClient } from "convex/browser"
import { assertAdminSession } from "@/lib/auth-server"
import { api } from "@/convex/_generated/api"
export const runtime = "nodejs"
export async function POST(request: Request) {
const session = await assertAdminSession()
if (!session) return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
const body = await request.json().catch(() => null) as { email?: string; companyId?: string }
const email = body?.email?.trim().toLowerCase()
const companyId = body?.companyId
if (!email || !companyId) {
return NextResponse.json({ error: "Informe e-mail e empresa" }, { status: 400 })
}
const convexUrl = process.env.NEXT_PUBLIC_CONVEX_URL
if (!convexUrl) return NextResponse.json({ error: "Convex não configurado" }, { status: 500 })
const client = new ConvexHttpClient(convexUrl)
try {
await client.mutation(api.users.assignCompany, {
tenantId: session.user.tenantId ?? "tenant-atlas",
email,
companyId: companyId as any,
actorId: (session.user as any).convexUserId ?? (session.user.id as any),
})
return NextResponse.json({ ok: true })
} catch (error) {
console.error("Failed to assign company", error)
return NextResponse.json({ error: "Falha ao vincular usuário" }, { status: 500 })
}
}