feat(reports): adiciona opcao Todas as empresas no relatorio por empresa

- Frontend: usa usePersistentCompanyFilter para persistir selecao
- Frontend: adiciona opcao "Todas as empresas" como primeira opcao
- Backend: torna companyId opcional na query companyOverview
- Backend: usa resolveScopedCompanyId para scoping de gestores

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
rever-tecnologia 2025-12-17 19:01:56 -03:00
parent 14480df9f3
commit 8a237a820d
2 changed files with 59 additions and 39 deletions

View file

@ -2406,18 +2406,20 @@ export const companyOverview = query({
args: {
tenantId: v.string(),
viewerId: v.id("users"),
companyId: v.id("companies"),
companyId: v.optional(v.id("companies")),
range: v.optional(v.string()),
},
handler: async (ctx, { tenantId, viewerId, companyId, range }) => {
const viewer = await requireStaff(ctx, viewerId, tenantId);
if (viewer.role === "MANAGER" && viewer.user.companyId && viewer.user.companyId !== companyId) {
throw new ConvexError("Gestores só podem consultar relatórios da própria empresa");
}
const scopedCompanyId = resolveScopedCompanyId(viewer, companyId);
const company = await ctx.db.get(companyId);
if (!company || company.tenantId !== tenantId) {
throw new ConvexError("Empresa não encontrada");
// Buscar dados da empresa selecionada (se houver)
let company: Doc<"companies"> | null = null;
if (scopedCompanyId) {
company = await ctx.db.get(scopedCompanyId);
if (!company || company.tenantId !== tenantId) {
throw new ConvexError("Empresa não encontrada");
}
}
const normalizedRange = (range ?? "30d").toLowerCase();
@ -2426,20 +2428,35 @@ export const companyOverview = query({
const startMs = now - rangeDays * ONE_DAY_MS;
// Limita consultas para evitar OOM em empresas muito grandes
const tickets = await ctx.db
.query("tickets")
.withIndex("by_tenant_company", (q) => q.eq("tenantId", tenantId).eq("companyId", companyId))
.take(2000);
const tickets = scopedCompanyId
? await ctx.db
.query("tickets")
.withIndex("by_tenant_company", (q) => q.eq("tenantId", tenantId).eq("companyId", scopedCompanyId))
.take(2000)
: await ctx.db
.query("tickets")
.withIndex("by_tenant", (q) => q.eq("tenantId", tenantId))
.take(2000);
const machines = await ctx.db
.query("machines")
.withIndex("by_tenant_company", (q) => q.eq("tenantId", tenantId).eq("companyId", companyId))
.take(1000);
const machines = scopedCompanyId
? await ctx.db
.query("machines")
.withIndex("by_tenant_company", (q) => q.eq("tenantId", tenantId).eq("companyId", scopedCompanyId))
.take(1000)
: await ctx.db
.query("machines")
.withIndex("by_tenant", (q) => q.eq("tenantId", tenantId))
.take(1000);
const users = await ctx.db
.query("users")
.withIndex("by_tenant_company", (q) => q.eq("tenantId", tenantId).eq("companyId", companyId))
.take(500);
const users = scopedCompanyId
? await ctx.db
.query("users")
.withIndex("by_tenant_company", (q) => q.eq("tenantId", tenantId).eq("companyId", scopedCompanyId))
.take(500)
: await ctx.db
.query("users")
.withIndex("by_tenant", (q) => q.eq("tenantId", tenantId))
.take(500);
const statusCounts = {} as Record<string, number>;
const priorityCounts = {} as Record<string, number>;
@ -2534,11 +2551,13 @@ export const companyOverview = query({
});
return {
company: {
id: company._id,
name: company.name,
isAvulso: company.isAvulso ?? false,
},
company: company
? {
id: company._id,
name: company.name,
isAvulso: company.isAvulso ?? false,
}
: null,
rangeDays,
generatedAt: now,
tickets: {