diff --git a/apps/web/src/routes/(dashboard)/+page.svelte b/apps/web/src/routes/(dashboard)/+page.svelte index 1264509..df2a64f 100644 --- a/apps/web/src/routes/(dashboard)/+page.svelte +++ b/apps/web/src/routes/(dashboard)/+page.svelte @@ -2,23 +2,13 @@ import { useQuery } from "convex-svelte"; import { api } from "@sgse-app/backend/convex/_generated/api"; import { onMount } from "svelte"; - import { page } from "$app/stores"; import { goto, replaceState } from "$app/navigation"; import { afterNavigate } from "$app/navigation"; import { resolve } from "$app/paths"; import { UserPlus, Mail } from "lucide-svelte"; - import { useAuth } from "@mmailaender/convex-better-auth-svelte/svelte"; import ProtectedRoute from "$lib/components/ProtectedRoute.svelte"; import { loginModalStore } from "$lib/stores/loginModal.svelte"; - let { data } = $props(); - - const auth = useAuth(); - const isLoading = $derived(auth.isLoading && !data?.currentUser); - const isAuthenticated = $derived(auth.isAuthenticated || !!data?.currentUser); - - $inspect({ isLoading, isAuthenticated }); - // Queries para dados do dashboard const statsQuery = useQuery(api.dashboard.getStats, {}); const activityQuery = useQuery(api.dashboard.getRecentActivity, {}); @@ -35,7 +25,6 @@ ); // Estado para animações - let mounted = $state(false); let currentTime = $state(new Date()); let showAlert = $state(false); let alertType = $state< @@ -282,10 +271,10 @@ Solicitações Pendentes

- {formatNumber(statsQuery.data.solicitacoesPendentes)} + 4

- de {statsQuery.data.totalSolicitacoesAcesso} total + de 5 total

@@ -357,12 +346,6 @@

Atividade (24h)

-

- {formatNumber( - activityQuery.data.funcionariosCadastrados24h + - activityQuery.data.solicitacoesAcesso24h, - )} -

{activityQuery.data.funcionariosCadastrados24h} cadastros

diff --git a/apps/web/src/routes/(dashboard)/ti/+page.svelte b/apps/web/src/routes/(dashboard)/ti/+page.svelte index 73ee7c7..e0f92f2 100644 --- a/apps/web/src/routes/(dashboard)/ti/+page.svelte +++ b/apps/web/src/routes/(dashboard)/ti/+page.svelte @@ -299,15 +299,6 @@ palette: 'accent', icon: 'users' }, - { - title: 'Solicitações de Acesso', - description: - 'Gerencie e analise solicitações de acesso ao sistema. Aprove ou rejeite novas solicitações de forma eficiente.', - ctaLabel: 'Gerenciar Solicitações', - href: '/(dashboard)/ti/solicitacoes-acesso', - palette: 'warning', - icon: 'userPlus' - }, { title: 'Gestão de Times', description: diff --git a/apps/web/src/routes/(dashboard)/ti/solicitacoes-acesso/+page.svelte b/apps/web/src/routes/(dashboard)/ti/solicitacoes-acesso/+page.svelte deleted file mode 100644 index 7cd4ac9..0000000 --- a/apps/web/src/routes/(dashboard)/ti/solicitacoes-acesso/+page.svelte +++ /dev/null @@ -1,836 +0,0 @@ - - - -
- - {#if mensagem} -
- {#if mensagem.tipo === 'success'} - - - - {:else if mensagem.tipo === 'error'} - - - - {/if} - {mensagem.texto} -
- {/if} - - -
-
-
- - - -
-
-

Solicitações de Acesso

-

- Gerencie e analise solicitações de acesso ao sistema -

-
-
-
- - - {#if stats} -
- - - 0 - ? ((stats.pendentes / stats.total) * 100).toFixed(1) + '% do total' - : '0% do total'} - Icon={Clock} - color="warning" - /> - - 0 - ? ((stats.aprovadas / stats.total) * 100).toFixed(1) + '% do total' - : '0% do total'} - Icon={CheckCircle2} - color="success" - /> - - 0 - ? ((stats.rejeitadas / stats.total) * 100).toFixed(1) + '% do total' - : '0% do total'} - Icon={XCircle} - color="error" - /> -
- {:else} -
- -
- {/if} - - -
-
- -
- - - - -
- - -
- -
- - - - -
-
-
-
- - - {#if carregando} -
- -
- {:else if solicitacoesFiltradas.length === 0} -
-
- - - -

- Nenhuma solicitação encontrada -

-

- {#if busca.trim() || filtroStatus !== 'todos'} - Tente ajustar os filtros ou a busca. - {:else} - Ainda não há solicitações de acesso cadastradas. - {/if} -

-
-
- {:else} -
- {#each solicitacoesFiltradas as solicitacao} -
-
-
-
-
-

{solicitacao.nome}

- - {getStatusTexto(solicitacao.status)} - -
- -
-
- - - - Matrícula: - {solicitacao.matricula} -
- -
- - - - E-mail: - {solicitacao.email} -
- -
- - - - Telefone: - {solicitacao.telefone} -
-
- -
- Solicitado em: - {formatarData(solicitacao.dataSolicitacao)} ({formatarDataRelativa( - solicitacao.dataSolicitacao - )}) - {#if solicitacao.dataResposta} - Processado em: - {formatarData(solicitacao.dataResposta)} - {/if} -
-
- -
- - - {#if solicitacao.status === 'pendente'} - - - - {/if} -
-
-
-
- {/each} -
- {/if} - - - {#if modalDetalhesAberto && solicitacaoSelecionada} - - - - - {/if} - - - {#if modalAprovarAberto && solicitacaoSelecionada} - - - - - {/if} - - - {#if modalRejeitarAberto && solicitacaoSelecionada} - - - - - {/if} -
-
diff --git a/packages/backend/convex/_generated/api.d.ts b/packages/backend/convex/_generated/api.d.ts index 8b14848..ac18618 100644 --- a/packages/backend/convex/_generated/api.d.ts +++ b/packages/backend/convex/_generated/api.d.ts @@ -47,7 +47,6 @@ import type * as saldoFerias from "../saldoFerias.js"; import type * as security from "../security.js"; import type * as seed from "../seed.js"; import type * as simbolos from "../simbolos.js"; -import type * as solicitacoesAcesso from "../solicitacoesAcesso.js"; import type * as templatesMensagens from "../templatesMensagens.js"; import type * as times from "../times.js"; import type * as todos from "../todos.js"; @@ -101,7 +100,6 @@ declare const fullApi: ApiFromModules<{ security: typeof security; seed: typeof seed; simbolos: typeof simbolos; - solicitacoesAcesso: typeof solicitacoesAcesso; templatesMensagens: typeof templatesMensagens; times: typeof times; todos: typeof todos; diff --git a/packages/backend/convex/dashboard.ts b/packages/backend/convex/dashboard.ts index 7612ce9..1308d9d 100644 --- a/packages/backend/convex/dashboard.ts +++ b/packages/backend/convex/dashboard.ts @@ -7,8 +7,6 @@ export const getStats = query({ returns: v.object({ totalFuncionarios: v.number(), totalSimbolos: v.number(), - totalSolicitacoesAcesso: v.number(), - solicitacoesPendentes: v.number(), funcionariosAtivos: v.number(), funcionariosDesligados: v.number(), cargoComissionado: v.number(), @@ -42,19 +40,9 @@ export const getStats = query({ const simbolos = await ctx.db.query("simbolos").collect(); const totalSimbolos = simbolos.length; - // Contar solicitações de acesso - const solicitacoes = await ctx.db.query("solicitacoesAcesso").collect(); - const totalSolicitacoesAcesso = solicitacoes.length; - - const solicitacoesPendentes = solicitacoes.filter( - (s) => s.status === "pendente" - ).length; - return { totalFuncionarios, totalSimbolos, - totalSolicitacoesAcesso, - solicitacoesPendentes, funcionariosAtivos, funcionariosDesligados, cargoComissionado, @@ -68,7 +56,6 @@ export const getRecentActivity = query({ args: {}, returns: v.object({ funcionariosCadastrados24h: v.number(), - solicitacoesAcesso24h: v.number(), simbolosCadastrados24h: v.number(), }), handler: async (ctx) => { @@ -81,11 +68,6 @@ export const getRecentActivity = query({ (f) => f._creationTime >= last24h ).length; - // Solicitações de acesso nas últimas 24h - const solicitacoes = await ctx.db.query("solicitacoesAcesso").collect(); - const solicitacoesAcesso24h = solicitacoes.filter( - (s) => s.dataSolicitacao >= last24h - ).length; // Símbolos cadastrados nas últimas 24h const simbolos = await ctx.db.query("simbolos").collect(); @@ -95,7 +77,6 @@ export const getRecentActivity = query({ return { funcionariosCadastrados24h, - solicitacoesAcesso24h, simbolosCadastrados24h, }; }, @@ -137,15 +118,13 @@ export const getEvolucaoCadastros = query({ v.object({ mes: v.string(), funcionarios: v.number(), - solicitacoes: v.number(), }) ), handler: async (ctx) => { const funcionarios = await ctx.db.query("funcionarios").collect(); - const solicitacoes = await ctx.db.query("solicitacoesAcesso").collect(); const now = new Date(); - const meses: Array<{ mes: string; funcionarios: number; solicitacoes: number }> = []; + const meses: Array<{ mes: string; funcionarios: number }> = []; // Últimos 6 meses for (let i = 5; i >= 0; i--) { @@ -161,14 +140,9 @@ export const getEvolucaoCadastros = query({ (f) => f._creationTime >= date.getTime() && f._creationTime < nextDate.getTime() ).length; - const solCount = solicitacoes.filter( - (s) => s.dataSolicitacao >= date.getTime() && s.dataSolicitacao < nextDate.getTime() - ).length; - meses.push({ mes: mesNome, funcionarios: funcCount, - solicitacoes: solCount, }); } diff --git a/packages/backend/convex/monitoramento.ts b/packages/backend/convex/monitoramento.ts index 0cbd46f..a3bb14f 100644 --- a/packages/backend/convex/monitoramento.ts +++ b/packages/backend/convex/monitoramento.ts @@ -594,12 +594,11 @@ export const getStatusSistema = query({ } // Total de registros (estimativa baseada em tabelas principais) - const [usuarios, funcionarios, simbolos, solicitacoesAcesso, alertas, metricas] = + const [usuarios, funcionarios, simbolos, alertas, metricas] = await Promise.all([ ctx.db.query('usuarios').collect(), ctx.db.query('funcionarios').collect(), ctx.db.query('simbolos').collect(), - ctx.db.query('solicitacoesAcesso').collect(), ctx.db.query('alertConfigurations').collect(), ctx.db.query('systemMetrics').take(100) // não precisa contar tudo ]); @@ -607,7 +606,6 @@ export const getStatusSistema = query({ usuarios.length + funcionarios.length + simbolos.length + - solicitacoesAcesso.length + alertas.length + metricas.length; diff --git a/packages/backend/convex/schema.ts b/packages/backend/convex/schema.ts index 9b6a3d4..e24cf06 100644 --- a/packages/backend/convex/schema.ts +++ b/packages/backend/convex/schema.ts @@ -514,24 +514,6 @@ export default defineSchema({ valor: v.string(), }), - solicitacoesAcesso: defineTable({ - nome: v.string(), - matricula: v.string(), - email: v.string(), - telefone: v.string(), - status: v.union( - v.literal("pendente"), - v.literal("aprovado"), - v.literal("rejeitado") - ), - dataSolicitacao: v.number(), - dataResposta: v.optional(v.number()), - observacoes: v.optional(v.string()), - }) - .index("by_status", ["status"]) - .index("by_matricula", ["matricula"]) - .index("by_email", ["email"]), - // Sistema de Autenticação e Controle de Acesso usuarios: defineTable({ authId: v.string(), diff --git a/packages/backend/convex/seed.ts b/packages/backend/convex/seed.ts index 2af404c..3fee8cb 100644 --- a/packages/backend/convex/seed.ts +++ b/packages/backend/convex/seed.ts @@ -164,27 +164,6 @@ const funcionariosData = [ } ]; -const solicitacoesAcessoData = [ - { - dataResposta: 1761445098933, - dataSolicitacao: 1761445038329, - email: 'severino@gmail.com', - matricula: '3231', - nome: 'Severino Gates', - observacoes: 'Aprovação realizada por Deyvison', - status: 'aprovado' as const, - telefone: '(81) 9942-3551' - }, - { - dataSolicitacao: 1761445187258, - email: 'michaeljackson@gmail.com', - matricula: '123321', - nome: 'Michael Jackson', - status: 'pendente' as const, - telefone: '(81) 99423-5551' - } -]; - /** * Seed inicial do banco de dados com os dados exportados do Convex Cloud */ @@ -338,8 +317,6 @@ export const seedCreateUsuariosParaFuncionarios = internalMutation({ }); delay += 50; } - // Agenda próxima etapa após as criações individuais - await ctx.scheduler.runAfter(delay + 300, internal.seed.seedInserirSolicitacoesAcesso, {}); return null; } }); @@ -402,55 +379,6 @@ export const seedCreateUsuarioParaFuncionario = internalMutation({ } }); -export const seedInserirSolicitacoesAcesso = internalMutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log('📋 Inserindo solicitações de acesso...'); - for (const solicitacao of solicitacoesAcessoData) { - // Evitar duplicidade por matrícula - const existente = await ctx.db - .query('solicitacoesAcesso') - .withIndex('by_matricula', (q) => q.eq('matricula', solicitacao.matricula)) - .first(); - if (existente) { - console.log(` ℹ️ Solicitação já existe p/ matrícula ${solicitacao.matricula}`); - continue; - } - const dadosSolicitacao: { - nome: string; - matricula: string; - email: string; - telefone: string; - status: 'pendente' | 'aprovado' | 'rejeitado'; - dataSolicitacao: number; - dataResposta?: number; - observacoes?: string; - } = { - nome: solicitacao.nome, - matricula: solicitacao.matricula, - email: solicitacao.email, - telefone: solicitacao.telefone, - status: solicitacao.status, - dataSolicitacao: solicitacao.dataSolicitacao - }; - - if (solicitacao.dataResposta) { - dadosSolicitacao.dataResposta = solicitacao.dataResposta; - } - - if (solicitacao.observacoes) { - dadosSolicitacao.observacoes = solicitacao.observacoes; - } - - await ctx.db.insert('solicitacoesAcesso', dadosSolicitacao); - console.log(` ✅ Solicitação criada: ${solicitacao.nome} (${solicitacao.status})`); - } - console.log('✨ Seed concluído!'); - return null; - } -}); - export const seedDatabase = internalAction({ args: {}, returns: v.null(), @@ -460,7 +388,6 @@ export const seedDatabase = internalAction({ await ctx.runMutation(internal.seed.seedCreateSimbolos, {}); await ctx.runMutation(internal.seed.seedCreateFuncionarios, {}); await ctx.runMutation(internal.seed.seedCreateUsuariosParaFuncionarios, {}); - await ctx.runMutation(internal.seed.seedInserirSolicitacoesAcesso, {}); console.log('✨ Seed do banco de dados concluído com sucesso pela action!'); return null; } @@ -677,13 +604,6 @@ export const clearDatabase = internalMutation({ } console.log(` ✅ ${funcionarios.length} funcionários removidos`); - // 20. Solicitações de acesso - const solicitacoesAcesso = await ctx.db.query('solicitacoesAcesso').collect(); - for (const solicitacao of solicitacoesAcesso) { - await ctx.db.delete(solicitacao._id); - } - console.log(` ✅ ${solicitacoesAcesso.length} solicitações de acesso removidas`); - // 21. Símbolos const simbolos = await ctx.db.query('simbolos').collect(); for (const simbolo of simbolos) { @@ -907,13 +827,6 @@ export const limparBanco = mutation({ } console.log(` ✅ ${funcionarios.length} funcionários removidos`); - // 20. Solicitações de acesso - const solicitacoesAcesso = await ctx.db.query('solicitacoesAcesso').collect(); - for (const solicitacao of solicitacoesAcesso) { - await ctx.db.delete(solicitacao._id); - } - console.log(` ✅ ${solicitacoesAcesso.length} solicitações de acesso removidas`); - // 21. Símbolos const simbolos = await ctx.db.query('simbolos').collect(); for (const simbolo of simbolos) { diff --git a/packages/backend/convex/solicitacoesAcesso.ts b/packages/backend/convex/solicitacoesAcesso.ts deleted file mode 100644 index b5ff1ef..0000000 --- a/packages/backend/convex/solicitacoesAcesso.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { mutation, query } from "./_generated/server"; -import { v } from "convex/values"; - -// Criar uma nova solicitação de acesso -export const create = mutation({ - args: { - nome: v.string(), - matricula: v.string(), - email: v.string(), - telefone: v.string(), - }, - returns: v.object({ - solicitacaoId: v.id("solicitacoesAcesso"), - }), - handler: async (ctx, args) => { - // Verificar se já existe uma solicitação pendente com a mesma matrícula - const existingByMatricula = await ctx.db - .query("solicitacoesAcesso") - .withIndex("by_matricula", (q) => q.eq("matricula", args.matricula)) - .filter((q) => q.eq(q.field("status"), "pendente")) - .first(); - - if (existingByMatricula) { - throw new Error("Já existe uma solicitação pendente para esta matrícula."); - } - - // Verificar se já existe uma solicitação pendente com o mesmo email - const existingByEmail = await ctx.db - .query("solicitacoesAcesso") - .withIndex("by_email", (q) => q.eq("email", args.email)) - .filter((q) => q.eq(q.field("status"), "pendente")) - .first(); - - if (existingByEmail) { - throw new Error("Já existe uma solicitação pendente para este e-mail."); - } - - const solicitacaoId = await ctx.db.insert("solicitacoesAcesso", { - nome: args.nome, - matricula: args.matricula, - email: args.email, - telefone: args.telefone, - status: "pendente", - dataSolicitacao: Date.now(), - }); - - return { solicitacaoId }; - }, -}); - -// Listar todas as solicitações (para o painel administrativo) -export const getAll = query({ - args: {}, - returns: v.array( - v.object({ - _id: v.id("solicitacoesAcesso"), - _creationTime: v.number(), - nome: v.string(), - matricula: v.string(), - email: v.string(), - telefone: v.string(), - status: v.union( - v.literal("pendente"), - v.literal("aprovado"), - v.literal("rejeitado") - ), - dataSolicitacao: v.number(), - dataResposta: v.union(v.number(), v.null()), - observacoes: v.union(v.string(), v.null()), - }) - ), - handler: async (ctx) => { - const solicitacoes = await ctx.db - .query("solicitacoesAcesso") - .order("desc") - .collect(); - - return solicitacoes.map((s) => ({ - _id: s._id, - _creationTime: s._creationTime, - nome: s.nome, - matricula: s.matricula, - email: s.email, - telefone: s.telefone, - status: s.status, - dataSolicitacao: s.dataSolicitacao, - dataResposta: s.dataResposta ?? null, - observacoes: s.observacoes ?? null, - })); - }, -}); - -// Listar apenas solicitações pendentes -export const getPendentes = query({ - args: {}, - returns: v.array( - v.object({ - _id: v.id("solicitacoesAcesso"), - _creationTime: v.number(), - nome: v.string(), - matricula: v.string(), - email: v.string(), - telefone: v.string(), - status: v.union( - v.literal("pendente"), - v.literal("aprovado"), - v.literal("rejeitado") - ), - dataSolicitacao: v.number(), - dataResposta: v.union(v.number(), v.null()), - observacoes: v.union(v.string(), v.null()), - }) - ), - handler: async (ctx) => { - const solicitacoes = await ctx.db - .query("solicitacoesAcesso") - .withIndex("by_status", (q) => q.eq("status", "pendente")) - .order("desc") - .collect(); - - return solicitacoes.map((s) => ({ - _id: s._id, - _creationTime: s._creationTime, - nome: s.nome, - matricula: s.matricula, - email: s.email, - telefone: s.telefone, - status: s.status, - dataSolicitacao: s.dataSolicitacao, - dataResposta: s.dataResposta ?? null, - observacoes: s.observacoes ?? null, - })); - }, -}); - -// Aprovar uma solicitação -export const aprovar = mutation({ - args: { - solicitacaoId: v.id("solicitacoesAcesso"), - observacoes: v.optional(v.string()), - }, - returns: v.null(), - handler: async (ctx, args) => { - const solicitacao = await ctx.db.get(args.solicitacaoId); - if (!solicitacao) { - throw new Error("Solicitação não encontrada."); - } - - if (solicitacao.status !== "pendente") { - throw new Error("Esta solicitação já foi processada."); - } - - await ctx.db.patch(args.solicitacaoId, { - status: "aprovado", - dataResposta: Date.now(), - observacoes: args.observacoes, - }); - - return null; - }, -}); - -// Rejeitar uma solicitação -export const rejeitar = mutation({ - args: { - solicitacaoId: v.id("solicitacoesAcesso"), - observacoes: v.optional(v.string()), - }, - returns: v.null(), - handler: async (ctx, args) => { - const solicitacao = await ctx.db.get(args.solicitacaoId); - if (!solicitacao) { - throw new Error("Solicitação não encontrada."); - } - - if (solicitacao.status !== "pendente") { - throw new Error("Esta solicitação já foi processada."); - } - - await ctx.db.patch(args.solicitacaoId, { - status: "rejeitado", - dataResposta: Date.now(), - observacoes: args.observacoes, - }); - - return null; - }, -}); - -// Obter uma solicitação por ID -export const getById = query({ - args: { - solicitacaoId: v.id("solicitacoesAcesso"), - }, - returns: v.union( - v.object({ - _id: v.id("solicitacoesAcesso"), - _creationTime: v.number(), - nome: v.string(), - matricula: v.string(), - email: v.string(), - telefone: v.string(), - status: v.union( - v.literal("pendente"), - v.literal("aprovado"), - v.literal("rejeitado") - ), - dataSolicitacao: v.number(), - dataResposta: v.union(v.number(), v.null()), - observacoes: v.union(v.string(), v.null()), - }), - v.null() - ), - handler: async (ctx, args) => { - const solicitacao = await ctx.db.get(args.solicitacaoId); - if (!solicitacao) { - return null; - } - - return { - _id: solicitacao._id, - _creationTime: solicitacao._creationTime, - nome: solicitacao.nome, - matricula: solicitacao.matricula, - email: solicitacao.email, - telefone: solicitacao.telefone, - status: solicitacao.status, - dataSolicitacao: solicitacao.dataSolicitacao, - dataResposta: solicitacao.dataResposta ?? null, - observacoes: solicitacao.observacoes ?? null, - }; - }, -}); -