feat: implement vacation management system with request approval, notification handling, and employee training tracking; enhance UI components for improved user experience
This commit is contained in:
270
packages/backend/convex/times.ts
Normal file
270
packages/backend/convex/times.ts
Normal file
@@ -0,0 +1,270 @@
|
||||
import { v } from "convex/values";
|
||||
import { mutation, query } from "./_generated/server";
|
||||
import { Id } from "./_generated/dataModel";
|
||||
|
||||
// Query: Listar todos os times
|
||||
export const listar = query({
|
||||
args: {},
|
||||
returns: v.array(v.any()),
|
||||
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
|
||||
export const obterPorId = query({
|
||||
args: { id: v.id("times") },
|
||||
returns: v.union(v.any(), v.null()),
|
||||
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
|
||||
export const obterTimeFuncionario = query({
|
||||
args: { funcionarioId: v.id("funcionarios") },
|
||||
returns: v.union(v.any(), v.null()),
|
||||
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
|
||||
export const listarPorGestor = query({
|
||||
args: { gestorId: v.id("usuarios") },
|
||||
returns: v.array(v.any()),
|
||||
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;
|
||||
},
|
||||
});
|
||||
|
||||
// Mutation: Criar time
|
||||
export const criar = mutation({
|
||||
args: {
|
||||
nome: v.string(),
|
||||
descricao: v.optional(v.string()),
|
||||
gestorId: 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,
|
||||
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"),
|
||||
cor: v.optional(v.string()),
|
||||
},
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
const { id, ...dados } = args;
|
||||
await ctx.db.patch(id, dados);
|
||||
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(),
|
||||
});
|
||||
}
|
||||
|
||||
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 membroId = await ctx.db.insert("timesMembros", {
|
||||
timeId: args.timeId,
|
||||
funcionarioId: args.funcionarioId,
|
||||
dataEntrada: Date.now(),
|
||||
ativo: true,
|
||||
});
|
||||
|
||||
return membroId;
|
||||
},
|
||||
});
|
||||
|
||||
// Mutation: Remover membro do time
|
||||
export const removerMembro = mutation({
|
||||
args: { membroId: v.id("timesMembros") },
|
||||
returns: v.null(),
|
||||
handler: async (ctx, args) => {
|
||||
await ctx.db.patch(args.membroId, {
|
||||
ativo: false,
|
||||
dataSaida: Date.now(),
|
||||
});
|
||||
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
|
||||
await ctx.db.insert("timesMembros", {
|
||||
timeId: args.novoTimeId,
|
||||
funcionarioId: args.funcionarioId,
|
||||
dataEntrada: Date.now(),
|
||||
ativo: true,
|
||||
});
|
||||
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user