feat: update ESLint and TypeScript configurations across frontend and backend; enhance component structure and improve data handling in various modules

This commit is contained in:
2025-12-02 16:36:02 -03:00
parent f48d28067c
commit d79e6959c3
215 changed files with 29474 additions and 28173 deletions

View File

@@ -1,365 +1,364 @@
import { v } from "convex/values";
import { mutation, query } from "./_generated/server";
import { getCurrentUserFunction } from "./auth";
import { v } from 'convex/values';
import { mutation, query } from './_generated/server';
import { getCurrentUserFunction } from './auth';
// Query: Listar todos os times
// Tipo inferido automaticamente pelo Convex
export const listar = query({
args: {},
handler: async (ctx) => {
const times = await ctx.db.query("times").collect();
// Buscar gestor e contar membros de cada time
const timesComDetalhes = await Promise.all(
times.map(async (time) => {
const gestor = await ctx.db.get(time.gestorId);
const membrosAtivos = await ctx.db
.query("timesMembros")
.withIndex("by_time_and_ativo", (q) => q.eq("timeId", time._id).eq("ativo", true))
.collect();
return {
...time,
gestor,
totalMembros: membrosAtivos.length,
};
})
);
return timesComDetalhes;
},
args: {},
handler: async (ctx) => {
const times = await ctx.db.query('times').collect();
// Buscar gestor e contar membros de cada time
const timesComDetalhes = await Promise.all(
times.map(async (time) => {
const gestor = await ctx.db.get(time.gestorId);
const membrosAtivos = await ctx.db
.query('timesMembros')
.withIndex('by_time_and_ativo', (q) => q.eq('timeId', time._id).eq('ativo', true))
.collect();
return {
...time,
gestor,
totalMembros: membrosAtivos.length
};
})
);
return timesComDetalhes;
}
});
// Query: Obter time por ID com membros
// Tipo inferido automaticamente pelo Convex
export const obterPorId = query({
args: { id: v.id("times") },
handler: async (ctx, args) => {
const time = await ctx.db.get(args.id);
if (!time) return null;
const gestor = await ctx.db.get(time.gestorId);
const membrosRelacoes = await ctx.db
.query("timesMembros")
.withIndex("by_time_and_ativo", (q) => q.eq("timeId", args.id).eq("ativo", true))
.collect();
// Buscar dados completos dos membros
const membros = await Promise.all(
membrosRelacoes.map(async (rel) => {
const funcionario = await ctx.db.get(rel.funcionarioId);
return {
...rel,
funcionario,
};
})
);
return {
...time,
gestor,
membros,
};
},
args: { id: v.id('times') },
handler: async (ctx, args) => {
const time = await ctx.db.get(args.id);
if (!time) return null;
const gestor = await ctx.db.get(time.gestorId);
const membrosRelacoes = await ctx.db
.query('timesMembros')
.withIndex('by_time_and_ativo', (q) => q.eq('timeId', args.id).eq('ativo', true))
.collect();
// Buscar dados completos dos membros
const membros = await Promise.all(
membrosRelacoes.map(async (rel) => {
const funcionario = await ctx.db.get(rel.funcionarioId);
return {
...rel,
funcionario
};
})
);
return {
...time,
gestor,
membros
};
}
});
// Query: Obter time do funcionário
// Tipo inferido automaticamente pelo Convex
export const obterTimeFuncionario = query({
args: { funcionarioId: v.id("funcionarios") },
handler: async (ctx, args) => {
const relacao = await ctx.db
.query("timesMembros")
.withIndex("by_funcionario", (q) => q.eq("funcionarioId", args.funcionarioId))
.filter((q) => q.eq(q.field("ativo"), true))
.first();
if (!relacao) return null;
const time = await ctx.db.get(relacao.timeId);
if (!time) return null;
const gestor = await ctx.db.get(time.gestorId);
return {
...time,
gestor,
};
},
args: { funcionarioId: v.id('funcionarios') },
handler: async (ctx, args) => {
const relacao = await ctx.db
.query('timesMembros')
.withIndex('by_funcionario', (q) => q.eq('funcionarioId', args.funcionarioId))
.filter((q) => q.eq(q.field('ativo'), true))
.first();
if (!relacao) return null;
const time = await ctx.db.get(relacao.timeId);
if (!time) return null;
const gestor = await ctx.db.get(time.gestorId);
return {
...time,
gestor
};
}
});
// Query: Obter times do gestor
// Tipo inferido automaticamente pelo Convex
export const listarPorGestor = query({
args: { gestorId: v.id("usuarios") },
handler: async (ctx, args) => {
const times = await ctx.db
.query("times")
.withIndex("by_gestor", (q) => q.eq("gestorId", args.gestorId))
.filter((q) => q.eq(q.field("ativo"), true))
.collect();
const timesComMembros = await Promise.all(
times.map(async (time) => {
const membrosRelacoes = await ctx.db
.query("timesMembros")
.withIndex("by_time_and_ativo", (q) => q.eq("timeId", time._id).eq("ativo", true))
.collect();
const membros = await Promise.all(
membrosRelacoes.map(async (rel) => {
const funcionario = await ctx.db.get(rel.funcionarioId);
return {
...rel,
funcionario,
};
})
);
return {
...time,
membros,
};
})
);
return timesComMembros;
},
args: { gestorId: v.id('usuarios') },
handler: async (ctx, args) => {
const times = await ctx.db
.query('times')
.withIndex('by_gestor', (q) => q.eq('gestorId', args.gestorId))
.filter((q) => q.eq(q.field('ativo'), true))
.collect();
const timesComMembros = await Promise.all(
times.map(async (time) => {
const membrosRelacoes = await ctx.db
.query('timesMembros')
.withIndex('by_time_and_ativo', (q) => q.eq('timeId', time._id).eq('ativo', true))
.collect();
const membros = await Promise.all(
membrosRelacoes.map(async (rel) => {
const funcionario = await ctx.db.get(rel.funcionarioId);
return {
...rel,
funcionario
};
})
);
return {
...time,
membros
};
})
);
return timesComMembros;
}
});
export const listarSubordinadosDoGestorAtual = query({
args: {},
handler: async (ctx) => {
const usuario = await getCurrentUserFunction(ctx);
if (!usuario) {
return [];
}
args: {},
handler: async (ctx) => {
const usuario = await getCurrentUserFunction(ctx);
if (!usuario) {
return [];
}
const timesGestor = await ctx.db
.query("times")
.withIndex("by_gestor", (q) => q.eq("gestorId", usuario._id))
.collect();
const timesGestor = await ctx.db
.query('times')
.withIndex('by_gestor', (q) => q.eq('gestorId', usuario._id))
.collect();
const timesComoSuperior = await ctx.db
.query("times")
.withIndex("by_gestor_superior", (q) => q.eq("gestorSuperiorId", usuario._id))
.collect();
const timesComoSuperior = await ctx.db
.query('times')
.withIndex('by_gestor_superior', (q) => q.eq('gestorSuperiorId', usuario._id))
.collect();
const timesMap = new Map(
[...timesGestor, ...timesComoSuperior]
.filter((time) => time.ativo)
.map((time) => [time._id, time])
);
const timesMap = new Map(
[...timesGestor, ...timesComoSuperior]
.filter((time) => time.ativo)
.map((time) => [time._id, time])
);
const resultado = [];
const resultado = [];
for (const time of timesMap.values()) {
const membrosRelacoes = await ctx.db
.query("timesMembros")
.withIndex("by_time_and_ativo", (q) => q.eq("timeId", time._id).eq("ativo", true))
.collect();
for (const time of timesMap.values()) {
const membrosRelacoes = await ctx.db
.query('timesMembros')
.withIndex('by_time_and_ativo', (q) => q.eq('timeId', time._id).eq('ativo', true))
.collect();
const membros = [];
for (const rel of membrosRelacoes) {
const funcionario = await ctx.db.get(rel.funcionarioId);
if (funcionario) {
// Buscar foto do perfil do funcionário através do usuário associado
let fotoPerfilUrl: string | null = null;
const usuario = await ctx.db
.query("usuarios")
.withIndex("by_funcionarioId", (q) => q.eq("funcionarioId", funcionario._id))
.first();
if (usuario?.fotoPerfil) {
fotoPerfilUrl = await ctx.storage.getUrl(usuario.fotoPerfil);
}
const membros = [];
for (const rel of membrosRelacoes) {
const funcionario = await ctx.db.get(rel.funcionarioId);
if (funcionario) {
// Buscar foto do perfil do funcionário através do usuário associado
let fotoPerfilUrl: string | null = null;
const usuario = await ctx.db
.query('usuarios')
.withIndex('by_funcionarioId', (q) => q.eq('funcionarioId', funcionario._id))
.first();
if (usuario?.fotoPerfil) {
fotoPerfilUrl = await ctx.storage.getUrl(usuario.fotoPerfil);
}
membros.push({
relacaoId: rel._id,
funcionario: {
...funcionario,
fotoPerfilUrl,
},
dataEntrada: rel.dataEntrada,
});
}
}
membros.push({
relacaoId: rel._id,
funcionario: {
...funcionario,
fotoPerfilUrl
},
dataEntrada: rel.dataEntrada
});
}
}
resultado.push({
...time,
membros,
});
}
resultado.push({
...time,
membros
});
}
return resultado;
},
return resultado;
}
});
// Mutation: Criar time
export const criar = mutation({
args: {
nome: v.string(),
descricao: v.optional(v.string()),
gestorId: v.id("usuarios"),
gestorSuperiorId: v.optional(v.id("usuarios")),
cor: v.optional(v.string()),
},
returns: v.id("times"),
handler: async (ctx, args) => {
const timeId = await ctx.db.insert("times", {
nome: args.nome,
descricao: args.descricao,
gestorId: args.gestorId,
gestorSuperiorId: args.gestorSuperiorId ?? args.gestorId,
ativo: true,
cor: args.cor || "#3B82F6",
});
return timeId;
},
args: {
nome: v.string(),
descricao: v.optional(v.string()),
gestorId: v.id('usuarios'),
gestorSuperiorId: v.optional(v.id('usuarios')),
cor: v.optional(v.string())
},
returns: v.id('times'),
handler: async (ctx, args) => {
const timeId = await ctx.db.insert('times', {
nome: args.nome,
descricao: args.descricao,
gestorId: args.gestorId,
gestorSuperiorId: args.gestorSuperiorId ?? args.gestorId,
ativo: true,
cor: args.cor || '#3B82F6'
});
return timeId;
}
});
// Mutation: Atualizar time
export const atualizar = mutation({
args: {
id: v.id("times"),
nome: v.string(),
descricao: v.optional(v.string()),
gestorId: v.id("usuarios"),
gestorSuperiorId: v.optional(v.id("usuarios")),
cor: v.optional(v.string()),
},
returns: v.null(),
handler: async (ctx, args) => {
const { id, ...dados } = args;
await ctx.db.patch(id, {
...dados,
gestorSuperiorId: dados.gestorSuperiorId ?? dados.gestorId,
});
return null;
},
args: {
id: v.id('times'),
nome: v.string(),
descricao: v.optional(v.string()),
gestorId: v.id('usuarios'),
gestorSuperiorId: v.optional(v.id('usuarios')),
cor: v.optional(v.string())
},
returns: v.null(),
handler: async (ctx, args) => {
const { id, ...dados } = args;
await ctx.db.patch(id, {
...dados,
gestorSuperiorId: dados.gestorSuperiorId ?? dados.gestorId
});
return null;
}
});
// Mutation: Desativar time
export const desativar = mutation({
args: { id: v.id("times") },
returns: v.null(),
handler: async (ctx, args) => {
// Desativar o time
await ctx.db.patch(args.id, { ativo: false });
// Desativar todos os membros
const membros = await ctx.db
.query("timesMembros")
.withIndex("by_time_and_ativo", (q) => q.eq("timeId", args.id).eq("ativo", true))
.collect();
for (const membro of membros) {
await ctx.db.patch(membro._id, {
ativo: false,
dataSaida: Date.now(),
});
args: { id: v.id('times') },
returns: v.null(),
handler: async (ctx, args) => {
// Desativar o time
await ctx.db.patch(args.id, { ativo: false });
await ctx.db.patch(membro.funcionarioId, { gestorId: undefined });
}
return null;
},
// Desativar todos os membros
const membros = await ctx.db
.query('timesMembros')
.withIndex('by_time_and_ativo', (q) => q.eq('timeId', args.id).eq('ativo', true))
.collect();
for (const membro of membros) {
await ctx.db.patch(membro._id, {
ativo: false,
dataSaida: Date.now()
});
await ctx.db.patch(membro.funcionarioId, { gestorId: undefined });
}
return null;
}
});
// Mutation: Adicionar membro ao time
export const adicionarMembro = mutation({
args: {
timeId: v.id("times"),
funcionarioId: v.id("funcionarios"),
},
returns: v.id("timesMembros"),
handler: async (ctx, args) => {
// Verificar se já não está em outro time ativo
const membroExistente = await ctx.db
.query("timesMembros")
.withIndex("by_funcionario", (q) => q.eq("funcionarioId", args.funcionarioId))
.filter((q) => q.eq(q.field("ativo"), true))
.first();
if (membroExistente) {
throw new Error("Funcionário já está em um time ativo");
}
const time = await ctx.db.get(args.timeId);
if (!time || !time.ativo) {
throw new Error("Time inválido ou inativo");
}
const membroId = await ctx.db.insert("timesMembros", {
timeId: args.timeId,
funcionarioId: args.funcionarioId,
dataEntrada: Date.now(),
ativo: true,
});
args: {
timeId: v.id('times'),
funcionarioId: v.id('funcionarios')
},
returns: v.id('timesMembros'),
handler: async (ctx, args) => {
// Verificar se já não está em outro time ativo
const membroExistente = await ctx.db
.query('timesMembros')
.withIndex('by_funcionario', (q) => q.eq('funcionarioId', args.funcionarioId))
.filter((q) => q.eq(q.field('ativo'), true))
.first();
await ctx.db.patch(args.funcionarioId, { gestorId: time.gestorId });
return membroId;
},
if (membroExistente) {
throw new Error('Funcionário já está em um time ativo');
}
const time = await ctx.db.get(args.timeId);
if (!time || !time.ativo) {
throw new Error('Time inválido ou inativo');
}
const membroId = await ctx.db.insert('timesMembros', {
timeId: args.timeId,
funcionarioId: args.funcionarioId,
dataEntrada: Date.now(),
ativo: true
});
await ctx.db.patch(args.funcionarioId, { gestorId: time.gestorId });
return membroId;
}
});
// Mutation: Remover membro do time
export const removerMembro = mutation({
args: { membroId: v.id("timesMembros") },
returns: v.null(),
handler: async (ctx, args) => {
const membro = await ctx.db.get(args.membroId);
if (!membro) {
throw new Error("Membro não encontrado");
}
await ctx.db.patch(args.membroId, {
ativo: false,
dataSaida: Date.now(),
});
args: { membroId: v.id('timesMembros') },
returns: v.null(),
handler: async (ctx, args) => {
const membro = await ctx.db.get(args.membroId);
if (!membro) {
throw new Error('Membro não encontrado');
}
await ctx.db.patch(args.membroId, {
ativo: false,
dataSaida: Date.now()
});
await ctx.db.patch(membro.funcionarioId, { gestorId: undefined });
return null;
},
await ctx.db.patch(membro.funcionarioId, { gestorId: undefined });
return null;
}
});
// Mutation: Transferir membro para outro time
export const transferirMembro = mutation({
args: {
funcionarioId: v.id("funcionarios"),
novoTimeId: v.id("times"),
},
returns: v.null(),
handler: async (ctx, args) => {
// Desativar do time atual
const relacaoAtual = await ctx.db
.query("timesMembros")
.withIndex("by_funcionario", (q) => q.eq("funcionarioId", args.funcionarioId))
.filter((q) => q.eq(q.field("ativo"), true))
.first();
if (relacaoAtual) {
await ctx.db.patch(relacaoAtual._id, {
ativo: false,
dataSaida: Date.now(),
});
}
// Adicionar ao novo time
const novoTime = await ctx.db.get(args.novoTimeId);
if (!novoTime || !novoTime.ativo) {
throw new Error("Novo time inválido ou inativo");
}
args: {
funcionarioId: v.id('funcionarios'),
novoTimeId: v.id('times')
},
returns: v.null(),
handler: async (ctx, args) => {
// Desativar do time atual
const relacaoAtual = await ctx.db
.query('timesMembros')
.withIndex('by_funcionario', (q) => q.eq('funcionarioId', args.funcionarioId))
.filter((q) => q.eq(q.field('ativo'), true))
.first();
await ctx.db.insert("timesMembros", {
timeId: args.novoTimeId,
funcionarioId: args.funcionarioId,
dataEntrada: Date.now(),
ativo: true,
});
if (relacaoAtual) {
await ctx.db.patch(relacaoAtual._id, {
ativo: false,
dataSaida: Date.now()
});
}
await ctx.db.patch(args.funcionarioId, { gestorId: novoTime.gestorId });
return null;
},
// Adicionar ao novo time
const novoTime = await ctx.db.get(args.novoTimeId);
if (!novoTime || !novoTime.ativo) {
throw new Error('Novo time inválido ou inativo');
}
await ctx.db.insert('timesMembros', {
timeId: args.novoTimeId,
funcionarioId: args.funcionarioId,
dataEntrada: Date.now(),
ativo: true
});
await ctx.db.patch(args.funcionarioId, { gestorId: novoTime.gestorId });
return null;
}
});