Fix usuarios page #6
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { useConvexClient } from "convex-svelte";
|
import { useConvexClient } from "convex-svelte";
|
||||||
import { api } from "@sgse-app/backend/convex/_generated/api";
|
import { api } from "@sgse-app/backend/convex/_generated/api";
|
||||||
|
import type { Id, Doc } from "@sgse-app/backend/convex/_generated/dataModel";
|
||||||
|
|
||||||
interface Periodo {
|
interface Periodo {
|
||||||
dataInicio: string;
|
dataInicio: string;
|
||||||
@@ -8,9 +9,14 @@
|
|||||||
diasCorridos: number;
|
diasCorridos: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SolicitacaoFerias = Doc<"solicitacoesFerias"> & {
|
||||||
|
funcionario?: Doc<"funcionarios"> | null;
|
||||||
|
gestor?: Doc<"usuarios"> | null;
|
||||||
|
};
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
solicitacao: any;
|
solicitacao: SolicitacaoFerias;
|
||||||
gestorId: string;
|
gestorId: Id<"usuarios">;
|
||||||
onSucesso?: () => void;
|
onSucesso?: () => void;
|
||||||
onCancelar?: () => void;
|
onCancelar?: () => void;
|
||||||
}
|
}
|
||||||
@@ -27,7 +33,7 @@
|
|||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (modoAjuste && periodos.length === 0) {
|
if (modoAjuste && periodos.length === 0) {
|
||||||
periodos = solicitacao.periodos.map((p: any) => ({...p}));
|
periodos = solicitacao.periodos.map((p) => ({...p}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -59,12 +65,12 @@
|
|||||||
|
|
||||||
await client.mutation(api.ferias.aprovar, {
|
await client.mutation(api.ferias.aprovar, {
|
||||||
solicitacaoId: solicitacao._id,
|
solicitacaoId: solicitacao._id,
|
||||||
gestorId: gestorId as any,
|
gestorId: gestorId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (onSucesso) onSucesso();
|
if (onSucesso) onSucesso();
|
||||||
} catch (e: any) {
|
} catch (e) {
|
||||||
erro = e.message || "Erro ao aprovar solicitação";
|
erro = e instanceof Error ? e.message : String(e);
|
||||||
} finally {
|
} finally {
|
||||||
processando = false;
|
processando = false;
|
||||||
}
|
}
|
||||||
@@ -82,13 +88,13 @@
|
|||||||
|
|
||||||
await client.mutation(api.ferias.reprovar, {
|
await client.mutation(api.ferias.reprovar, {
|
||||||
solicitacaoId: solicitacao._id,
|
solicitacaoId: solicitacao._id,
|
||||||
gestorId: gestorId as any,
|
gestorId: gestorId,
|
||||||
motivoReprovacao,
|
motivoReprovacao,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (onSucesso) onSucesso();
|
if (onSucesso) onSucesso();
|
||||||
} catch (e: any) {
|
} catch (e) {
|
||||||
erro = e.message || "Erro ao reprovar solicitação";
|
erro = e instanceof Error ? e.message : String(e);
|
||||||
} finally {
|
} finally {
|
||||||
processando = false;
|
processando = false;
|
||||||
}
|
}
|
||||||
@@ -101,13 +107,13 @@
|
|||||||
|
|
||||||
await client.mutation(api.ferias.ajustarEAprovar, {
|
await client.mutation(api.ferias.ajustarEAprovar, {
|
||||||
solicitacaoId: solicitacao._id,
|
solicitacaoId: solicitacao._id,
|
||||||
gestorId: gestorId as any,
|
gestorId: gestorId,
|
||||||
novosPeriodos: periodos,
|
novosPeriodos: periodos,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (onSucesso) onSucesso();
|
if (onSucesso) onSucesso();
|
||||||
} catch (e: any) {
|
} catch (e) {
|
||||||
erro = e.message || "Erro ao ajustar e aprovar solicitação";
|
erro = e instanceof Error ? e.message : String(e);
|
||||||
} finally {
|
} finally {
|
||||||
processando = false;
|
processando = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,10 +110,16 @@ class AuthStore {
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (usuarioAtualizado && this.state.usuario) {
|
if (usuarioAtualizado) {
|
||||||
|
// Preservar role e primeiroAcesso do estado atual
|
||||||
this.state.usuario = {
|
this.state.usuario = {
|
||||||
...this.state.usuario,
|
|
||||||
...usuarioAtualizado,
|
...usuarioAtualizado,
|
||||||
|
role: this.state.usuario?.role || {
|
||||||
|
_id: "",
|
||||||
|
nome: "Usuário",
|
||||||
|
nivel: 999,
|
||||||
|
},
|
||||||
|
primeiroAcesso: this.state.usuario?.primeiroAcesso ?? false,
|
||||||
};
|
};
|
||||||
|
|
||||||
localStorage.setItem(
|
localStorage.setItem(
|
||||||
|
|||||||
@@ -39,7 +39,11 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$inspect(authStore.usuario?.funcionarioId);
|
// Debug: Verificar funcionarioId
|
||||||
|
$effect(() => {
|
||||||
|
console.log("🔍 [Perfil] funcionarioId:", authStore.usuario?.funcionarioId);
|
||||||
|
console.log("🔍 [Perfil] Usuário completo:", authStore.usuario);
|
||||||
|
});
|
||||||
|
|
||||||
// Queries
|
// Queries
|
||||||
const funcionarioQuery = $derived(
|
const funcionarioQuery = $derived(
|
||||||
|
|||||||
@@ -9,15 +9,16 @@ import {
|
|||||||
} from "./auth/utils";
|
} from "./auth/utils";
|
||||||
import { registrarLogin } from "./logsLogin";
|
import { registrarLogin } from "./logsLogin";
|
||||||
import { Id } from "./_generated/dataModel";
|
import { Id } from "./_generated/dataModel";
|
||||||
|
import type { QueryCtx } from "./_generated/server";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper para verificar se usuário está bloqueado
|
* Helper para verificar se usuário está bloqueado
|
||||||
*/
|
*/
|
||||||
async function verificarBloqueioUsuario(ctx: any, usuarioId: Id<"usuarios">) {
|
async function verificarBloqueioUsuario(ctx: QueryCtx, usuarioId: Id<"usuarios">) {
|
||||||
const bloqueio = await ctx.db
|
const bloqueio = await ctx.db
|
||||||
.query("bloqueiosUsuarios")
|
.query("bloqueiosUsuarios")
|
||||||
.withIndex("by_usuario", (q: any) => q.eq("usuarioId", usuarioId))
|
.withIndex("by_usuario", (q) => q.eq("usuarioId", usuarioId))
|
||||||
.filter((q: any) => q.eq(q.field("ativo"), true))
|
.filter((q) => q.eq(q.field("ativo"), true))
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
return bloqueio !== null;
|
return bloqueio !== null;
|
||||||
@@ -26,17 +27,17 @@ async function verificarBloqueioUsuario(ctx: any, usuarioId: Id<"usuarios">) {
|
|||||||
/**
|
/**
|
||||||
* Helper para verificar rate limiting por IP
|
* Helper para verificar rate limiting por IP
|
||||||
*/
|
*/
|
||||||
async function verificarRateLimitIP(ctx: any, ipAddress: string) {
|
async function verificarRateLimitIP(ctx: QueryCtx, ipAddress: string) {
|
||||||
// Últimas 15 minutos
|
// Últimas 15 minutos
|
||||||
const dataLimite = Date.now() - 15 * 60 * 1000;
|
const dataLimite = Date.now() - 15 * 60 * 1000;
|
||||||
|
|
||||||
const tentativas = await ctx.db
|
const tentativas = await ctx.db
|
||||||
.query("logsLogin")
|
.query("logsLogin")
|
||||||
.withIndex("by_ip", (q: any) => q.eq("ipAddress", ipAddress))
|
.withIndex("by_ip", (q) => q.eq("ipAddress", ipAddress))
|
||||||
.filter((q: any) => q.gte(q.field("timestamp"), dataLimite))
|
.filter((q) => q.gte(q.field("timestamp"), dataLimite))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
const falhas = tentativas.filter((t: any) => !t.sucesso).length;
|
const falhas = tentativas.filter((t) => !t.sucesso).length;
|
||||||
|
|
||||||
// Bloquear se 5 ou mais tentativas falhas em 15 minutos
|
// Bloquear se 5 ou mais tentativas falhas em 15 minutos
|
||||||
return falhas >= 5;
|
return falhas >= 5;
|
||||||
@@ -299,6 +300,7 @@ export const login = mutation({
|
|||||||
matricula: usuario.matricula,
|
matricula: usuario.matricula,
|
||||||
nome: usuario.nome,
|
nome: usuario.nome,
|
||||||
email: usuario.email,
|
email: usuario.email,
|
||||||
|
funcionarioId: usuario.funcionarioId,
|
||||||
role: {
|
role: {
|
||||||
_id: role._id,
|
_id: role._id,
|
||||||
nome: role.nome,
|
nome: role.nome,
|
||||||
|
|||||||
@@ -20,11 +20,12 @@ async function getUsuarioAutenticado(ctx: QueryCtx | MutationCtx) {
|
|||||||
.first();
|
.first();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Se não encontrou via Better Auth, tentar via sessão
|
// Se não encontrou via Better Auth, tentar via sessão mais recente
|
||||||
if (!usuarioAtual) {
|
if (!usuarioAtual) {
|
||||||
const sessaoAtiva = await ctx.db
|
const sessaoAtiva = await ctx.db
|
||||||
.query("sessoes")
|
.query("sessoes")
|
||||||
.filter((q) => q.eq(q.field("ativo"), true))
|
.filter((q) => q.eq(q.field("ativo"), true))
|
||||||
|
.order("desc")
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
if (sessaoAtiva) {
|
if (sessaoAtiva) {
|
||||||
@@ -875,7 +876,7 @@ export const buscarMensagens = query({
|
|||||||
c.participantes.includes(usuarioAtual._id)
|
c.participantes.includes(usuarioAtual._id)
|
||||||
);
|
);
|
||||||
|
|
||||||
let mensagens: any[] = [];
|
let mensagens: Doc<"mensagens">[] = [];
|
||||||
|
|
||||||
if (args.conversaId !== undefined) {
|
if (args.conversaId !== undefined) {
|
||||||
// Buscar em conversa específica
|
// Buscar em conversa específica
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ export const salvarConfigEmail = mutation({
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Testar conexão SMTP (action - precisa de Node.js)
|
* Testar conexão SMTP (action - precisa de Node.js)
|
||||||
*
|
*
|
||||||
* NOTA: Esta action será implementada quando instalarmos nodemailer.
|
* NOTA: Esta action será implementada quando instalarmos nodemailer.
|
||||||
* Por enquanto, retorna sucesso simulado para não bloquear o desenvolvimento.
|
* Por enquanto, retorna sucesso simulado para não bloquear o desenvolvimento.
|
||||||
*/
|
*/
|
||||||
@@ -126,11 +126,14 @@ export const testarConexaoSMTP = action({
|
|||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
// TODO: Implementar teste real com nodemailer
|
// TODO: Implementar teste real com nodemailer
|
||||||
// Por enquanto, simula sucesso
|
// Por enquanto, simula sucesso
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Validações básicas
|
// Validações básicas
|
||||||
if (!args.servidor || args.servidor.trim() === "") {
|
if (!args.servidor || args.servidor.trim() === "") {
|
||||||
return { sucesso: false as const, erro: "Servidor SMTP não pode estar vazio" };
|
return {
|
||||||
|
sucesso: false as const,
|
||||||
|
erro: "Servidor SMTP não pode estar vazio",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.porta < 1 || args.porta > 65535) {
|
if (args.porta < 1 || args.porta > 65535) {
|
||||||
@@ -141,10 +144,17 @@ export const testarConexaoSMTP = action({
|
|||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
|
||||||
// Retornar sucesso simulado
|
// Retornar sucesso simulado
|
||||||
console.log("⚠️ AVISO: Teste de conexão SMTP simulado (nodemailer não instalado ainda)");
|
console.log(
|
||||||
|
"⚠️ AVISO: Teste de conexão SMTP simulado (nodemailer não instalado ainda)"
|
||||||
|
);
|
||||||
return { sucesso: true as const };
|
return { sucesso: true as const };
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
return { sucesso: false as const, erro: error.message || "Erro ao testar conexão" };
|
const errorMessage =
|
||||||
|
error instanceof Error ? error.message : String(error);
|
||||||
|
return {
|
||||||
|
sucesso: false as const,
|
||||||
|
erro: errorMessage || "Erro ao testar conexão",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -162,5 +172,3 @@ export const marcarConfigTestada = mutation({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export const updateDocumento = mutation({
|
|||||||
// Atualizar o campo específico do documento
|
// Atualizar o campo específico do documento
|
||||||
await ctx.db.patch(args.funcionarioId, {
|
await ctx.db.patch(args.funcionarioId, {
|
||||||
[args.campo]: args.storageId,
|
[args.campo]: args.storageId,
|
||||||
} as any);
|
});
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
@@ -106,7 +106,7 @@ export const getDocumentosUrls = query({
|
|||||||
];
|
];
|
||||||
|
|
||||||
for (const campo of campos) {
|
for (const campo of campos) {
|
||||||
const storageId = (funcionario as any)[campo];
|
const storageId = funcionario[campo as keyof typeof funcionario] as Id<"_storage"> | undefined;
|
||||||
if (storageId) {
|
if (storageId) {
|
||||||
urls[campo] = await ctx.storage.getUrl(storageId);
|
urls[campo] = await ctx.storage.getUrl(storageId);
|
||||||
} else {
|
} else {
|
||||||
@@ -114,7 +114,7 @@ export const getDocumentosUrls = query({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return urls as any;
|
return urls;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
} from "./_generated/server";
|
} from "./_generated/server";
|
||||||
import { Id } from "./_generated/dataModel";
|
import { Id } from "./_generated/dataModel";
|
||||||
import { renderizarTemplate } from "./templatesMensagens";
|
import { renderizarTemplate } from "./templatesMensagens";
|
||||||
import { internal } from "./_generated/api";
|
import { internal, api } from "./_generated/api";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enfileirar email para envio
|
* Enfileirar email para envio
|
||||||
@@ -58,7 +58,7 @@ export const enviarEmailComTemplate = mutation({
|
|||||||
destinatario: v.string(),
|
destinatario: v.string(),
|
||||||
destinatarioId: v.optional(v.id("usuarios")),
|
destinatarioId: v.optional(v.id("usuarios")),
|
||||||
templateCodigo: v.string(),
|
templateCodigo: v.string(),
|
||||||
variaveis: v.any(), // Record<string, string>
|
variaveis: v.record(v.string(), v.string()),
|
||||||
enviadoPorId: v.id("usuarios"),
|
enviadoPorId: v.id("usuarios"),
|
||||||
},
|
},
|
||||||
returns: v.object({
|
returns: v.object({
|
||||||
@@ -113,7 +113,7 @@ export const listarFilaEmails = query({
|
|||||||
),
|
),
|
||||||
limite: v.optional(v.number()),
|
limite: v.optional(v.number()),
|
||||||
},
|
},
|
||||||
returns: v.array(v.any()),
|
// Tipo inferido automaticamente pelo Convex
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
if (args.status) {
|
if (args.status) {
|
||||||
const emails = await ctx.db
|
const emails = await ctx.db
|
||||||
@@ -166,7 +166,7 @@ export const reenviarEmail = mutation({
|
|||||||
*/
|
*/
|
||||||
export const getEmailById = internalQuery({
|
export const getEmailById = internalQuery({
|
||||||
args: { emailId: v.id("notificacoesEmail") },
|
args: { emailId: v.id("notificacoesEmail") },
|
||||||
returns: v.union(v.any(), v.null()),
|
// Tipo inferido automaticamente pelo Convex
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
return await ctx.db.get(args.emailId);
|
return await ctx.db.get(args.emailId);
|
||||||
},
|
},
|
||||||
@@ -174,7 +174,7 @@ export const getEmailById = internalQuery({
|
|||||||
|
|
||||||
export const getActiveEmailConfig = internalQuery({
|
export const getActiveEmailConfig = internalQuery({
|
||||||
args: {},
|
args: {},
|
||||||
returns: v.union(v.any(), v.null()),
|
// Tipo inferido automaticamente pelo Convex
|
||||||
handler: async (ctx) => {
|
handler: async (ctx) => {
|
||||||
return await ctx.db
|
return await ctx.db
|
||||||
.query("configuracaoEmail")
|
.query("configuracaoEmail")
|
||||||
@@ -188,9 +188,10 @@ export const markEmailEnviando = internalMutation({
|
|||||||
returns: v.null(),
|
returns: v.null(),
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
const email = await ctx.db.get(args.emailId);
|
const email = await ctx.db.get(args.emailId);
|
||||||
|
if (!email) return null;
|
||||||
await ctx.db.patch(args.emailId, {
|
await ctx.db.patch(args.emailId, {
|
||||||
status: "enviando",
|
status: "enviando",
|
||||||
tentativas: ((email as any)?.tentativas || 0) + 1,
|
tentativas: (email.tentativas || 0) + 1,
|
||||||
ultimaTentativa: Date.now(),
|
ultimaTentativa: Date.now(),
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
@@ -214,10 +215,11 @@ export const markEmailFalha = internalMutation({
|
|||||||
returns: v.null(),
|
returns: v.null(),
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
const email = await ctx.db.get(args.emailId);
|
const email = await ctx.db.get(args.emailId);
|
||||||
|
if (!email) return null;
|
||||||
await ctx.db.patch(args.emailId, {
|
await ctx.db.patch(args.emailId, {
|
||||||
status: "falha",
|
status: "falha",
|
||||||
erroDetalhes: args.erro,
|
erroDetalhes: args.erro,
|
||||||
tentativas: ((email as any)?.tentativas || 0) + 1,
|
tentativas: (email.tentativas || 0) + 1,
|
||||||
});
|
});
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
@@ -270,12 +272,12 @@ export const enviarEmailAction = action({
|
|||||||
|
|
||||||
// Criar transporter do nodemailer
|
// Criar transporter do nodemailer
|
||||||
const transporter = nodemailer.createTransport({
|
const transporter = nodemailer.createTransport({
|
||||||
host: (config as any).smtpHost,
|
host: config.servidor,
|
||||||
port: (config as any).smtpPort,
|
port: config.porta,
|
||||||
secure: (config as any).smtpSecure,
|
secure: config.usarSSL,
|
||||||
auth: {
|
auth: {
|
||||||
user: (config as any).smtpUser,
|
user: config.usuario,
|
||||||
pass: (config as any).smtpPassword,
|
pass: config.senhaHash, // Note: em produção deve ser descriptografado
|
||||||
},
|
},
|
||||||
tls: {
|
tls: {
|
||||||
rejectUnauthorized: false,
|
rejectUnauthorized: false,
|
||||||
@@ -284,15 +286,15 @@ export const enviarEmailAction = action({
|
|||||||
|
|
||||||
// Enviar email REAL
|
// Enviar email REAL
|
||||||
const info = await transporter.sendMail({
|
const info = await transporter.sendMail({
|
||||||
from: `"${(config as any).remetenteNome}" <${(config as any).remetenteEmail}>`,
|
from: `"${config.nomeRemetente}" <${config.emailRemetente}>`,
|
||||||
to: (email as any).destinatario,
|
to: email.destinatario,
|
||||||
subject: (email as any).assunto,
|
subject: email.assunto,
|
||||||
html: (email as any).corpo,
|
html: email.corpo,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("✅ Email enviado com sucesso!");
|
console.log("✅ Email enviado com sucesso!");
|
||||||
console.log(" Para:", (email as any).destinatario);
|
console.log(" Para:", email.destinatario);
|
||||||
console.log(" Assunto:", (email as any).assunto);
|
console.log(" Assunto:", email.assunto);
|
||||||
console.log(" Message ID:", info.messageId);
|
console.log(" Message ID:", info.messageId);
|
||||||
|
|
||||||
// Marcar como enviado
|
// Marcar como enviado
|
||||||
@@ -301,16 +303,18 @@ export const enviarEmailAction = action({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return { sucesso: true };
|
return { sucesso: true };
|
||||||
} catch (error: any) {
|
} catch (error) {
|
||||||
console.error("❌ Erro ao enviar email:", error.message);
|
const errorMessage =
|
||||||
|
error instanceof Error ? error.message : String(error);
|
||||||
|
console.error("❌ Erro ao enviar email:", errorMessage);
|
||||||
|
|
||||||
// Marcar como falha
|
// Marcar como falha
|
||||||
await ctx.runMutation(internal.email.markEmailFalha, {
|
await ctx.runMutation(internal.email.markEmailFalha, {
|
||||||
emailId: args.emailId,
|
emailId: args.emailId,
|
||||||
erro: error.message || "Erro ao enviar email",
|
erro: errorMessage,
|
||||||
});
|
});
|
||||||
|
|
||||||
return { sucesso: false, erro: error.message || "Erro ao enviar email" };
|
return { sucesso: false, erro: errorMessage };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -342,7 +346,7 @@ export const processarFilaEmails = internalMutation({
|
|||||||
|
|
||||||
// Agendar envio via action
|
// Agendar envio via action
|
||||||
// IMPORTANTE: Não podemos chamar action diretamente de mutation
|
// IMPORTANTE: Não podemos chamar action diretamente de mutation
|
||||||
// Por isso, usaremos o scheduler
|
// Por isso, usaremos o scheduler com string path
|
||||||
await ctx.scheduler.runAfter(0, "email:enviarEmailAction" as any, {
|
await ctx.scheduler.runAfter(0, "email:enviarEmailAction" as any, {
|
||||||
emailId: email._id,
|
emailId: email._id,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { v } from "convex/values";
|
import { v } from "convex/values";
|
||||||
import { mutation, query, internalMutation } from "./_generated/server";
|
import { mutation, query, internalMutation } from "./_generated/server";
|
||||||
import { internal } from "./_generated/api";
|
import { internal } from "./_generated/api";
|
||||||
import { Id } from "./_generated/dataModel";
|
import { Id, Doc } from "./_generated/dataModel";
|
||||||
|
|
||||||
// Validador para períodos
|
// Validador para períodos
|
||||||
const periodoValidator = v.object({
|
const periodoValidator = v.object({
|
||||||
@@ -11,9 +11,9 @@ const periodoValidator = v.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Query: Listar TODAS as solicitações (para RH)
|
// Query: Listar TODAS as solicitações (para RH)
|
||||||
|
// Retorna tipo inferido automaticamente pelo Convex
|
||||||
export const listarTodas = query({
|
export const listarTodas = query({
|
||||||
args: {},
|
args: {},
|
||||||
returns: v.array(v.any()),
|
|
||||||
handler: async (ctx) => {
|
handler: async (ctx) => {
|
||||||
const solicitacoes = await ctx.db.query("solicitacoesFerias").collect();
|
const solicitacoes = await ctx.db.query("solicitacoesFerias").collect();
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ export const listarTodas = query({
|
|||||||
// Query: Listar solicitações do funcionário
|
// Query: Listar solicitações do funcionário
|
||||||
export const listarMinhasSolicitacoes = query({
|
export const listarMinhasSolicitacoes = query({
|
||||||
args: { funcionarioId: v.id("funcionarios") },
|
args: { funcionarioId: v.id("funcionarios") },
|
||||||
returns: v.array(v.any()),
|
// returns não especificado - TypeScript inferirá automaticamente o tipo correto
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
return await ctx.db
|
return await ctx.db
|
||||||
.query("solicitacoesFerias")
|
.query("solicitacoesFerias")
|
||||||
@@ -65,9 +65,9 @@ export const listarMinhasSolicitacoes = query({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Query: Listar solicitações dos subordinados (para gestores)
|
// Query: Listar solicitações dos subordinados (para gestores)
|
||||||
|
// Retorna tipo inferido automaticamente pelo Convex
|
||||||
export const listarSolicitacoesSubordinados = query({
|
export const listarSolicitacoesSubordinados = query({
|
||||||
args: { gestorId: v.id("usuarios") },
|
args: { gestorId: v.id("usuarios") },
|
||||||
returns: v.array(v.any()),
|
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
// Buscar times onde o usuário é gestor
|
// Buscar times onde o usuário é gestor
|
||||||
const timesGestor = await ctx.db
|
const timesGestor = await ctx.db
|
||||||
@@ -76,7 +76,10 @@ export const listarSolicitacoesSubordinados = query({
|
|||||||
.filter((q) => q.eq(q.field("ativo"), true))
|
.filter((q) => q.eq(q.field("ativo"), true))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
const solicitacoes: Array<any> = [];
|
const solicitacoes: Array<Doc<"solicitacoesFerias"> & {
|
||||||
|
funcionario: Doc<"funcionarios"> | null;
|
||||||
|
time: Doc<"times"> | null;
|
||||||
|
}> = [];
|
||||||
|
|
||||||
for (const time of timesGestor) {
|
for (const time of timesGestor) {
|
||||||
// Buscar membros do time
|
// Buscar membros do time
|
||||||
@@ -113,9 +116,9 @@ export const listarSolicitacoesSubordinados = query({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Query: Obter detalhes completos de uma solicitação
|
// Query: Obter detalhes completos de uma solicitação
|
||||||
|
// Retorna tipo inferido automaticamente pelo Convex
|
||||||
export const obterDetalhes = query({
|
export const obterDetalhes = query({
|
||||||
args: { solicitacaoId: v.id("solicitacoesFerias") },
|
args: { solicitacaoId: v.id("solicitacoesFerias") },
|
||||||
returns: v.union(v.any(), v.null()),
|
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
const solicitacao = await ctx.db.get(args.solicitacaoId);
|
const solicitacao = await ctx.db.get(args.solicitacaoId);
|
||||||
if (!solicitacao) return null;
|
if (!solicitacao) return null;
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export const getAll = query({
|
|||||||
|
|
||||||
export const getById = query({
|
export const getById = query({
|
||||||
args: { id: v.id("funcionarios") },
|
args: { id: v.id("funcionarios") },
|
||||||
returns: v.union(v.any(), v.null()),
|
// Tipo inferido automaticamente pelo Convex
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
// Autorização: ver funcionário
|
// Autorização: ver funcionário
|
||||||
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
|
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
|
||||||
@@ -205,7 +205,7 @@ export const create = mutation({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const novoFuncionarioId = await ctx.db.insert("funcionarios", args as any);
|
const novoFuncionarioId = await ctx.db.insert("funcionarios", args);
|
||||||
return novoFuncionarioId;
|
return novoFuncionarioId;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -335,7 +335,7 @@ export const update = mutation({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { id, ...updateData } = args;
|
const { id, ...updateData } = args;
|
||||||
await ctx.db.patch(id, updateData as any);
|
await ctx.db.patch(id, updateData);
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -358,7 +358,7 @@ export const remove = mutation({
|
|||||||
// Query para obter ficha completa para impressão
|
// Query para obter ficha completa para impressão
|
||||||
export const getFichaCompleta = query({
|
export const getFichaCompleta = query({
|
||||||
args: { id: v.id("funcionarios") },
|
args: { id: v.id("funcionarios") },
|
||||||
returns: v.union(v.any(), v.null()),
|
// Tipo inferido automaticamente pelo Convex
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
|
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
|
||||||
recurso: "funcionarios",
|
recurso: "funcionarios",
|
||||||
@@ -398,11 +398,10 @@ export const getFichaCompleta = query({
|
|||||||
? {
|
? {
|
||||||
nome: simbolo.nome,
|
nome: simbolo.nome,
|
||||||
descricao: simbolo.descricao,
|
descricao: simbolo.descricao,
|
||||||
// campos adicionais, se existirem no símbolo
|
tipo: simbolo.tipo,
|
||||||
tipo: (simbolo as any).tipo,
|
vencValor: simbolo.vencValor,
|
||||||
vencValor: (simbolo as any).vencValor,
|
repValor: simbolo.repValor,
|
||||||
repValor: (simbolo as any).repValor,
|
valor: simbolo.valor,
|
||||||
valor: (simbolo as any).valor,
|
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
cursos: cursosComUrls,
|
cursos: cursosComUrls,
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export const executar = internalMutation({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. Agrupar funcionários por gestor
|
// 2. Agrupar funcionários por gestor
|
||||||
const gestoresMap = new Map<string, any[]>();
|
const gestoresMap = new Map<string, Doc<"funcionarios">[]>();
|
||||||
|
|
||||||
for (const funcionario of funcionariosComGestor) {
|
for (const funcionario of funcionariosComGestor) {
|
||||||
if (!funcionario.gestorId) continue;
|
if (!funcionario.gestorId) continue;
|
||||||
@@ -53,7 +53,7 @@ export const executar = internalMutation({
|
|||||||
// 3. Para cada gestor, criar um time
|
// 3. Para cada gestor, criar um time
|
||||||
for (const [gestorId, subordinados] of gestoresMap.entries()) {
|
for (const [gestorId, subordinados] of gestoresMap.entries()) {
|
||||||
try {
|
try {
|
||||||
const gestor = await ctx.db.get(gestorId as any);
|
const gestor = await ctx.db.get(gestorId);
|
||||||
|
|
||||||
if (!gestor) {
|
if (!gestor) {
|
||||||
erros.push(`Gestor ${gestorId} não encontrado`);
|
erros.push(`Gestor ${gestorId} não encontrado`);
|
||||||
@@ -63,7 +63,7 @@ export const executar = internalMutation({
|
|||||||
// Verificar se já existe time para este gestor
|
// Verificar se já existe time para este gestor
|
||||||
const timeExistente = await ctx.db
|
const timeExistente = await ctx.db
|
||||||
.query("times")
|
.query("times")
|
||||||
.withIndex("by_gestor", (q) => q.eq("gestorId", gestorId as any))
|
.withIndex("by_gestor", (q) => q.eq("gestorId", gestorId))
|
||||||
.filter((q) => q.eq(q.field("ativo"), true))
|
.filter((q) => q.eq(q.field("ativo"), true))
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ export const executar = internalMutation({
|
|||||||
timeId = await ctx.db.insert("times", {
|
timeId = await ctx.db.insert("times", {
|
||||||
nome: `Equipe ${gestor.nome}`,
|
nome: `Equipe ${gestor.nome}`,
|
||||||
descricao: `Time gerenciado por ${gestor.nome} (migração automática)`,
|
descricao: `Time gerenciado por ${gestor.nome} (migração automática)`,
|
||||||
gestorId: gestorId as any,
|
gestorId: gestorId,
|
||||||
ativo: true,
|
ativo: true,
|
||||||
cor: "#3B82F6",
|
cor: "#3B82F6",
|
||||||
});
|
});
|
||||||
@@ -102,7 +102,7 @@ export const executar = internalMutation({
|
|||||||
});
|
});
|
||||||
funcionariosAtribuidos++;
|
funcionariosAtribuidos++;
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e) {
|
||||||
erros.push(`Erro ao adicionar ${funcionario.nome} ao time: ${e.message}`);
|
erros.push(`Erro ao adicionar ${funcionario.nome} ao time: ${e.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import { v } from "convex/values";
|
import { v } from "convex/values";
|
||||||
import { mutation, query, internalMutation } from "./_generated/server";
|
import { mutation, query, internalMutation } from "./_generated/server";
|
||||||
import { internal } from "./_generated/api";
|
import { internal } from "./_generated/api";
|
||||||
import { Id } from "./_generated/dataModel";
|
import { Id, Doc } from "./_generated/dataModel";
|
||||||
|
import type { QueryCtx } from "./_generated/server";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper para obter usuário autenticado
|
* Helper para obter usuário autenticado
|
||||||
*/
|
*/
|
||||||
async function getUsuarioAutenticado(ctx: any) {
|
async function getUsuarioAutenticado(ctx: QueryCtx) {
|
||||||
const usuariosOnline = await ctx.db.query("usuarios").collect();
|
const usuariosOnline = await ctx.db.query("usuarios").collect();
|
||||||
const usuarioOnline = usuariosOnline.find(
|
const usuarioOnline = usuariosOnline.find(
|
||||||
(u: any) => u.statusPresenca === "online"
|
(u) => u.statusPresenca === "online"
|
||||||
);
|
);
|
||||||
return usuarioOnline || null;
|
return usuarioOnline || null;
|
||||||
}
|
}
|
||||||
@@ -298,7 +299,7 @@ export const verificarAlertasInternal = internalMutation({
|
|||||||
|
|
||||||
for (const alerta of alertasAtivos) {
|
for (const alerta of alertasAtivos) {
|
||||||
// Obter valor da métrica correspondente
|
// Obter valor da métrica correspondente
|
||||||
const metricValue = (metrica as any)[alerta.metricName];
|
const metricValue = (metrica as Record<string, number>)[alerta.metricName];
|
||||||
|
|
||||||
if (metricValue === undefined) continue;
|
if (metricValue === undefined) continue;
|
||||||
|
|
||||||
@@ -355,7 +356,7 @@ export const verificarAlertasInternal = internalMutation({
|
|||||||
// Buscar usuários TI para notificar
|
// Buscar usuários TI para notificar
|
||||||
const usuarios = await ctx.db.query("usuarios").collect();
|
const usuarios = await ctx.db.query("usuarios").collect();
|
||||||
const usuariosTI = usuarios.filter(
|
const usuariosTI = usuarios.filter(
|
||||||
(u: any) => u.role?.nome === "ti" || u.role?.nivel === 0
|
(u) => u.role?.nome === "ti" || u.role?.nivel === 0
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const usuario of usuariosTI) {
|
for (const usuario of usuariosTI) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { Id } from "./_generated/dataModel";
|
|||||||
*/
|
*/
|
||||||
export const listarPerfisCustomizados = query({
|
export const listarPerfisCustomizados = query({
|
||||||
args: {},
|
args: {},
|
||||||
returns: v.array(v.any()),
|
// Tipo inferido automaticamente pelo Convex
|
||||||
handler: async (ctx) => {
|
handler: async (ctx) => {
|
||||||
const perfis = await ctx.db.query("perfisCustomizados").collect();
|
const perfis = await ctx.db.query("perfisCustomizados").collect();
|
||||||
|
|
||||||
@@ -47,11 +47,11 @@ export const obterPerfilComPermissoes = query({
|
|||||||
},
|
},
|
||||||
returns: v.union(
|
returns: v.union(
|
||||||
v.object({
|
v.object({
|
||||||
perfil: v.any(),
|
perfil: v.any(), // Doc<"perfisCustomizados"> não pode ser validado diretamente
|
||||||
role: v.any(),
|
role: v.any(), // Doc<"roles"> não pode ser validado diretamente
|
||||||
permissoes: v.array(v.any()),
|
permissoes: v.array(v.any()), // Doc<"permissoes">[] não pode ser validado diretamente
|
||||||
menuPermissoes: v.array(v.any()),
|
menuPermissoes: v.array(v.any()), // Doc<"menuPermissoes">[] não pode ser validado diretamente
|
||||||
usuarios: v.array(v.any()),
|
usuarios: v.array(v.any()), // Doc<"usuarios">[] não pode ser validado diretamente
|
||||||
}),
|
}),
|
||||||
v.null()
|
v.null()
|
||||||
),
|
),
|
||||||
@@ -227,7 +227,7 @@ export const editarPerfilCustomizado = mutation({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Atualizar perfil
|
// Atualizar perfil
|
||||||
const updates: any = {
|
const updates: Partial<Doc<"perfisCustomizados">> & { atualizadoEm: number } = {
|
||||||
atualizadoEm: Date.now(),
|
atualizadoEm: Date.now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -419,7 +419,7 @@ export const clonarPerfil = mutation({
|
|||||||
|
|
||||||
// Log de atividade
|
// Log de atividade
|
||||||
await registrarAtividade(
|
await registrarAtividade(
|
||||||
ctx as any,
|
ctx,
|
||||||
args.criadoPorId,
|
args.criadoPorId,
|
||||||
"criar",
|
"criar",
|
||||||
"perfis",
|
"perfis",
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ export const assertPermissaoAcaoAtual = internalQuery({
|
|||||||
returns: v.null(),
|
returns: v.null(),
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
const identity = await ctx.auth.getUserIdentity();
|
const identity = await ctx.auth.getUserIdentity();
|
||||||
let usuarioAtual: any = null;
|
let usuarioAtual: Doc<"usuarios"> | null = null;
|
||||||
|
|
||||||
if (identity && identity.email) {
|
if (identity && identity.email) {
|
||||||
usuarioAtual = await ctx.db
|
usuarioAtual = await ctx.db
|
||||||
@@ -187,9 +187,9 @@ export const assertPermissaoAcaoAtual = internalQuery({
|
|||||||
|
|
||||||
if (!usuarioAtual) throw new Error("acesso_negado");
|
if (!usuarioAtual) throw new Error("acesso_negado");
|
||||||
|
|
||||||
const role: any = await ctx.db.get(usuarioAtual.roleId as any);
|
const role = await ctx.db.get(usuarioAtual.roleId);
|
||||||
if (!role) throw new Error("acesso_negado");
|
if (!role) throw new Error("acesso_negado");
|
||||||
if ((role as any).nivel <= 1) return null;
|
if (role.nivel <= 1) return null;
|
||||||
|
|
||||||
const permissao = await ctx.db
|
const permissao = await ctx.db
|
||||||
.query("permissoes")
|
.query("permissoes")
|
||||||
@@ -201,7 +201,7 @@ export const assertPermissaoAcaoAtual = internalQuery({
|
|||||||
|
|
||||||
const links = await ctx.db
|
const links = await ctx.db
|
||||||
.query("rolePermissoes")
|
.query("rolePermissoes")
|
||||||
.withIndex("by_role", (q) => q.eq("roleId", (role as any)._id as any))
|
.withIndex("by_role", (q) => q.eq("roleId", role._id))
|
||||||
.collect();
|
.collect();
|
||||||
const ok = links.some((rp) => rp.permissaoId === permissao!._id);
|
const ok = links.some((rp) => rp.permissaoId === permissao!._id);
|
||||||
if (!ok) throw new Error("acesso_negado");
|
if (!ok) throw new Error("acesso_negado");
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ function calcularDataFimPeriodo(dataAdmissao: string, anosPassados: number): str
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper: Obter regime de trabalho do funcionário
|
// Helper: Obter regime de trabalho do funcionário
|
||||||
async function obterRegimeTrabalho(ctx: any, funcionarioId: Id<"funcionarios">): Promise<RegimeTrabalho> {
|
async function obterRegimeTrabalho(ctx: QueryCtx, funcionarioId: Id<"funcionarios">): Promise<RegimeTrabalho> {
|
||||||
const funcionario = await ctx.db.get(funcionarioId);
|
const funcionario = await ctx.db.get(funcionarioId);
|
||||||
return funcionario?.regimeTrabalho || "clt"; // Default CLT
|
return funcionario?.regimeTrabalho || "clt"; // Default CLT
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { v } from "convex/values";
|
import { v } from "convex/values";
|
||||||
import { mutation, query } from "./_generated/server";
|
import { mutation, query } from "./_generated/server";
|
||||||
import { registrarAtividade } from "./logsAtividades";
|
import { registrarAtividade } from "./logsAtividades";
|
||||||
|
import { Doc } from "./_generated/dataModel";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listar todos os templates
|
* Listar todos os templates
|
||||||
@@ -111,7 +112,7 @@ export const editarTemplate = mutation({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Atualizar template
|
// Atualizar template
|
||||||
const updates: any = {};
|
const updates: Partial<Doc<"templatesMensagens">> = {};
|
||||||
if (args.nome !== undefined) updates.nome = args.nome;
|
if (args.nome !== undefined) updates.nome = args.nome;
|
||||||
if (args.titulo !== undefined) updates.titulo = args.titulo;
|
if (args.titulo !== undefined) updates.titulo = args.titulo;
|
||||||
if (args.corpo !== undefined) updates.corpo = args.corpo;
|
if (args.corpo !== undefined) updates.corpo = args.corpo;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { v } from "convex/values";
|
import { v } from "convex/values";
|
||||||
import { mutation, query } from "./_generated/server";
|
import { mutation, query } from "./_generated/server";
|
||||||
import { Id } from "./_generated/dataModel";
|
import { Id, Doc } from "./_generated/dataModel";
|
||||||
|
|
||||||
// Query: Listar todos os times
|
// Query: Listar todos os times
|
||||||
|
// Tipo inferido automaticamente pelo Convex
|
||||||
export const listar = query({
|
export const listar = query({
|
||||||
args: {},
|
args: {},
|
||||||
returns: v.array(v.any()),
|
|
||||||
handler: async (ctx) => {
|
handler: async (ctx) => {
|
||||||
const times = await ctx.db.query("times").collect();
|
const times = await ctx.db.query("times").collect();
|
||||||
|
|
||||||
@@ -31,9 +31,9 @@ export const listar = query({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Query: Obter time por ID com membros
|
// Query: Obter time por ID com membros
|
||||||
|
// Tipo inferido automaticamente pelo Convex
|
||||||
export const obterPorId = query({
|
export const obterPorId = query({
|
||||||
args: { id: v.id("times") },
|
args: { id: v.id("times") },
|
||||||
returns: v.union(v.any(), v.null()),
|
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
const time = await ctx.db.get(args.id);
|
const time = await ctx.db.get(args.id);
|
||||||
if (!time) return null;
|
if (!time) return null;
|
||||||
@@ -64,9 +64,9 @@ export const obterPorId = query({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Query: Obter time do funcionário
|
// Query: Obter time do funcionário
|
||||||
|
// Tipo inferido automaticamente pelo Convex
|
||||||
export const obterTimeFuncionario = query({
|
export const obterTimeFuncionario = query({
|
||||||
args: { funcionarioId: v.id("funcionarios") },
|
args: { funcionarioId: v.id("funcionarios") },
|
||||||
returns: v.union(v.any(), v.null()),
|
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
const relacao = await ctx.db
|
const relacao = await ctx.db
|
||||||
.query("timesMembros")
|
.query("timesMembros")
|
||||||
@@ -89,9 +89,9 @@ export const obterTimeFuncionario = query({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Query: Obter times do gestor
|
// Query: Obter times do gestor
|
||||||
|
// Tipo inferido automaticamente pelo Convex
|
||||||
export const listarPorGestor = query({
|
export const listarPorGestor = query({
|
||||||
args: { gestorId: v.id("usuarios") },
|
args: { gestorId: v.id("usuarios") },
|
||||||
returns: v.array(v.any()),
|
|
||||||
handler: async (ctx, args) => {
|
handler: async (ctx, args) => {
|
||||||
const times = await ctx.db
|
const times = await ctx.db
|
||||||
.query("times")
|
.query("times")
|
||||||
|
|||||||
@@ -11,15 +11,22 @@
|
|||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"types": [],
|
||||||
/* These compiler options are required by Convex */
|
/* These compiler options are required by Convex */
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
"lib": ["ES2021", "dom"],
|
"lib": [
|
||||||
|
"ES2021",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"noEmit": true
|
"noEmit": true
|
||||||
},
|
},
|
||||||
"include": ["./**/*"],
|
"include": [
|
||||||
"exclude": ["./_generated"]
|
"./**/*"
|
||||||
}
|
],
|
||||||
|
"exclude": [
|
||||||
|
"./_generated"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ import { v } from "convex/values";
|
|||||||
import { mutation, query } from "./_generated/server";
|
import { mutation, query } from "./_generated/server";
|
||||||
import { hashPassword, generateToken } from "./auth/utils";
|
import { hashPassword, generateToken } from "./auth/utils";
|
||||||
import { registrarAtividade } from "./logsAtividades";
|
import { registrarAtividade } from "./logsAtividades";
|
||||||
import { Id } from "./_generated/dataModel";
|
import { Id, Doc } from "./_generated/dataModel";
|
||||||
import { api } from "./_generated/api";
|
import { api } from "./_generated/api";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -436,7 +436,7 @@ export const atualizarPerfil = mutation({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Atualizar apenas os campos fornecidos
|
// Atualizar apenas os campos fornecidos
|
||||||
const updates: any = { atualizadoEm: Date.now() };
|
const updates: Partial<Doc<"usuarios">> & { atualizadoEm: number } = { atualizadoEm: Date.now() };
|
||||||
|
|
||||||
if (args.avatar !== undefined) updates.avatar = args.avatar;
|
if (args.avatar !== undefined) updates.avatar = args.avatar;
|
||||||
if (args.fotoPerfil !== undefined) updates.fotoPerfil = args.fotoPerfil;
|
if (args.fotoPerfil !== undefined) updates.fotoPerfil = args.fotoPerfil;
|
||||||
@@ -882,7 +882,7 @@ export const editarUsuario = mutation({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Atualizar campos fornecidos
|
// Atualizar campos fornecidos
|
||||||
const updates: any = {
|
const updates: Partial<Doc<"usuarios">> & { atualizadoEm: number } = {
|
||||||
atualizadoEm: Date.now(),
|
atualizadoEm: Date.now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { internalMutation, query } from "./_generated/server";
|
import { internalMutation, query } from "./_generated/server";
|
||||||
import { v } from "convex/values";
|
import { v } from "convex/values";
|
||||||
|
import { Id, Doc } from "./_generated/dataModel";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verificar duplicatas de matrícula
|
* Verificar duplicatas de matrícula
|
||||||
@@ -33,7 +34,7 @@ export const verificarDuplicatas = query({
|
|||||||
email: usuario.email || "",
|
email: usuario.email || "",
|
||||||
});
|
});
|
||||||
return acc;
|
return acc;
|
||||||
}, {} as Record<string, any[]>);
|
}, {} as Record<string, Array<{ _id: Id<"usuarios">; nome: string; email: string }>>);
|
||||||
|
|
||||||
// Filtrar apenas duplicatas
|
// Filtrar apenas duplicatas
|
||||||
const duplicatas = Object.entries(gruposPorMatricula)
|
const duplicatas = Object.entries(gruposPorMatricula)
|
||||||
@@ -67,7 +68,7 @@ export const removerDuplicatas = internalMutation({
|
|||||||
}
|
}
|
||||||
acc[usuario.matricula].push(usuario);
|
acc[usuario.matricula].push(usuario);
|
||||||
return acc;
|
return acc;
|
||||||
}, {} as Record<string, any[]>);
|
}, {} as Record<string, Doc<"usuarios">[]>);
|
||||||
|
|
||||||
let removidos = 0;
|
let removidos = 0;
|
||||||
const matriculasDuplicadas: string[] = [];
|
const matriculasDuplicadas: string[] = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user