From 34e4835c81b3c61c90f399502962c75b715484ff Mon Sep 17 00:00:00 2001 From: killer-cf Date: Wed, 12 Nov 2025 19:03:36 -0300 Subject: [PATCH 1/8] chore: update convex and convex-svelte dependencies - Bumped convex version from 1.28.0 to 1.28.2 for improved functionality. - Updated convex-svelte version from 0.0.11 to 0.0.12 to incorporate the latest features and fixes. --- apps/web/package.json | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 61cc60c..8eb81c6 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -44,7 +44,7 @@ "@types/papaparse": "^5.3.14", "better-auth": "catalog:", "convex": "catalog:", - "convex-svelte": "^0.0.11", + "convex-svelte": "^0.0.12", "date-fns": "^4.1.0", "emoji-picker-element": "^1.27.0", "is-network-error": "^1.3.0", diff --git a/package.json b/package.json index c2c84bd..bb85f3d 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "packages/*" ], "catalog": { - "convex": "^1.28.0", + "convex": "^1.28.2", "typescript": "^5.9.2", "better-auth": "1.3.27", "eslint": "^9.39.1", @@ -44,4 +44,4 @@ "svelte-sonner": "^1.0.5" }, "packageManager": "bun@1.3.0" -} +} \ No newline at end of file -- 2.49.1 From a2451baafc70cac562db6f2ef7957e022ed25d6f Mon Sep 17 00:00:00 2001 From: killer-cf Date: Wed, 12 Nov 2025 20:00:01 -0300 Subject: [PATCH 2/8] Use $app/paths resolve for internal URLs and clean code``` --- AGENTS.md | 23 +++++++++++ .../ti/usuarios/criar/+page.svelte | 38 +++++++------------ 2 files changed, 37 insertions(+), 24 deletions(-) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..a6e66ff --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,23 @@ +You are able to use the Svelte MCP server, where you have access to comprehensive Svelte 5 and SvelteKit documentation. Here's how to use the available tools effectively: + +## Available MCP Tools: + +### 1. list-sections + +Use this FIRST to discover all available documentation sections. Returns a structured list with titles, use_cases, and paths. +When asked about Svelte or SvelteKit topics, ALWAYS use this tool at the start of the chat to find relevant sections. + +### 2. get-documentation + +Retrieves full documentation content for specific sections. Accepts single or multiple sections. +After calling the list-sections tool, you MUST analyze the returned documentation sections (especially the use_cases field) and then use the get-documentation tool to fetch ALL documentation sections that are relevant for the user's task. + +### 3. svelte-autofixer + +Analyzes Svelte code and returns issues and suggestions. +You MUST use this tool whenever writing Svelte code before sending it to the user. Keep calling it until no issues or suggestions are returned. + +### 4. playground-link + +Generates a Svelte Playground link with the provided code. +After completing the code, ask the user if they want a playground link. Only call this tool after user confirmation and NEVER if code was written to files in their project. diff --git a/apps/web/src/routes/(dashboard)/ti/usuarios/criar/+page.svelte b/apps/web/src/routes/(dashboard)/ti/usuarios/criar/+page.svelte index de91390..4b5bf41 100644 --- a/apps/web/src/routes/(dashboard)/ti/usuarios/criar/+page.svelte +++ b/apps/web/src/routes/(dashboard)/ti/usuarios/criar/+page.svelte @@ -2,6 +2,7 @@ import { useQuery, useConvexClient } from 'convex-svelte'; import { api } from '@sgse-app/backend/convex/_generated/api'; import { goto } from '$app/navigation'; + import { resolve } from '$app/paths'; import type { Id } from '@sgse-app/backend/convex/_generated/dataModel'; import ProtectedRoute from '$lib/components/ProtectedRoute.svelte'; @@ -9,18 +10,6 @@ const roles = useQuery(api.roles.listar, {}); const funcionarios = useQuery(api.funcionarios.getAll, {}); - // Debug - Remover após teste - $effect(() => { - console.log('=== DEBUG PERFIS ==='); - console.log('roles:', roles); - console.log('roles?.data:', roles?.data); - console.log('É array?', Array.isArray(roles?.data)); - if (roles?.data) { - console.log('Quantidade de perfis:', roles.data.length); - console.log('Perfis:', roles.data); - } - }); - // Estados do formulário let nome = $state(''); let email = $state(''); @@ -75,19 +64,20 @@ `Usuário criado! SENHA TEMPORÁRIA: ${senhaGerada} - Anote esta senha, ela não será exibida novamente!` ); setTimeout(() => { - goto('/ti/usuarios'); + goto(resolve('/ti/usuarios')); }, 5000); } else { mostrarMensagem('success', 'Usuário criado com sucesso!'); setTimeout(() => { - goto('/ti/usuarios'); + goto(resolve('/ti/usuarios')); }, 2000); } } else { mostrarMensagem('error', resultado.erro); } - } catch (error: any) { - mostrarMensagem('error', error.message || 'Erro ao criar usuário'); + } catch (error: unknown) { + const message = error instanceof Error ? error.message : String(error); + mostrarMensagem('error', message || 'Erro ao criar usuário'); } finally { processando = false; } @@ -99,7 +89,7 @@ // Auto-completar ao selecionar funcionário $effect(() => { if (funcionarioId && funcionarios?.data) { - const funcSelecionado = funcionarios.data.find((f: any) => f._id === funcionarioId); + const funcSelecionado = funcionarios.data.find((f) => f._id === funcionarioId); if (funcSelecionado) { email = funcSelecionado.email || email; nome = funcSelecionado.nome || nome; @@ -154,7 +144,7 @@

Cadastre um novo usuário no sistema

- + @@ -254,7 +244,7 @@ > {#if funcionarios?.data} - {#each funcionarios.data as func} + {#each funcionarios.data as func (func._id)} {/each} {/if} @@ -312,7 +302,7 @@ > {#if roles?.data && Array.isArray(roles.data)} - {#each roles.data as role} + {#each roles.data as role (role._id)} @@ -484,7 +474,7 @@
  • O usuário deverá alterar a senha no primeiro acesso
  • As credenciais devem ser repassadas manualmente (por enquanto)
  • - Configure o SMTP em Configurações de Email para envio automático
  • @@ -493,7 +483,7 @@
    - + Date: Wed, 12 Nov 2025 23:18:41 -0300 Subject: [PATCH 3/8] Use resolve() for all internal hrefs and goto paths to ensure correct routing --- apps/web/src/lib/components/Sidebar.svelte | 2 +- apps/web/src/routes/(dashboard)/+page.svelte | 11 ++-- .../(dashboard)/alterar-senha/+page.svelte | 9 +-- .../routes/(dashboard)/compras/+page.svelte | 3 +- .../(dashboard)/comunicacao/+page.svelte | 3 +- .../(dashboard)/controladoria/+page.svelte | 3 +- .../(dashboard)/esqueci-senha/+page.svelte | 7 ++- .../(dashboard)/financeiro/+page.svelte | 3 +- .../(dashboard)/gestao-pessoas/+page.svelte | 3 +- .../gestao-ausencias/+page.svelte | 5 +- .../routes/(dashboard)/juridico/+page.svelte | 3 +- .../(dashboard)/licitacoes/+page.svelte | 3 +- .../programas-esportivos/+page.svelte | 3 +- .../atestados-licencas/+page.svelte | 5 +- .../recursos-humanos/ausencias/+page.svelte | 5 +- .../funcionarios/+page.svelte | 7 ++- .../funcionarios/[funcionarioId]/+page.svelte | 17 +++--- .../[funcionarioId]/documentos/+page.svelte | 13 ++-- .../[funcionarioId]/editar/+page.svelte | 9 +-- .../funcionarios/excluir/+page.svelte | 9 +-- .../funcionarios/relatorios/+page.svelte | 61 ++++++++++--------- .../recursos-humanos/simbolos/+page.svelte | 7 ++- .../simbolos/[simboloId]/editar/+page.svelte | 5 +- .../simbolos/cadastro/+page.svelte | 9 +-- .../secretaria-executiva/+page.svelte | 3 +- .../gestao-ausencias/+page.svelte | 5 +- .../(dashboard)/solicitar-acesso/+page.svelte | 5 +- .../(dashboard)/ti/auditoria/+page.svelte | 16 ++--- .../ti/painel-administrativo/+page.svelte | 53 ++++++++-------- .../routes/(dashboard)/ti/perfis/+page.svelte | 5 +- .../ti/personalizar-permissoes/+page.svelte | 9 +-- .../(dashboard)/ti/usuarios/+page.svelte | 3 +- 32 files changed, 168 insertions(+), 136 deletions(-) diff --git a/apps/web/src/lib/components/Sidebar.svelte b/apps/web/src/lib/components/Sidebar.svelte index 282c574..1d1e1cc 100644 --- a/apps/web/src/lib/components/Sidebar.svelte +++ b/apps/web/src/lib/components/Sidebar.svelte @@ -366,7 +366,7 @@ {@const isActive = currentPath.startsWith(s.link)}
  • diff --git a/apps/web/src/routes/(dashboard)/+page.svelte b/apps/web/src/routes/(dashboard)/+page.svelte index 750841a..0c7070b 100644 --- a/apps/web/src/routes/(dashboard)/+page.svelte +++ b/apps/web/src/routes/(dashboard)/+page.svelte @@ -4,6 +4,7 @@ import { onMount } from "svelte"; import { page } from "$app/stores"; import { goto } from "$app/navigation"; + import { resolve } from "$app/paths"; import { UserPlus, Mail } from "lucide-svelte"; import { useAuth } from "@mmailaender/convex-better-auth-svelte/svelte"; @@ -145,7 +146,7 @@

    {alertData.message}

    {#if alertType === "access_denied"}
    - + Solicitar Acesso - + Contatar TI @@ -781,19 +782,19 @@

    Acesso Rápido

    Novo Funcionário Novo Símbolo Painel Admin diff --git a/apps/web/src/routes/(dashboard)/alterar-senha/+page.svelte b/apps/web/src/routes/(dashboard)/alterar-senha/+page.svelte index 11ca82d..a2a96d1 100644 --- a/apps/web/src/routes/(dashboard)/alterar-senha/+page.svelte +++ b/apps/web/src/routes/(dashboard)/alterar-senha/+page.svelte @@ -3,6 +3,7 @@ import { api } from '@sgse-app/backend/convex/_generated/api'; import { authStore } from '$lib/stores/auth.svelte'; import { goto } from '$app/navigation'; + import { resolve } from '$app/paths'; import { onMount } from 'svelte'; const convex = useConvexClient(); @@ -19,7 +20,7 @@ onMount(() => { if (!currentUser?.data) { - goto('/'); + goto(resolve('/')); } }); @@ -112,7 +113,7 @@ // Redirecionar após 2 segundos setTimeout(() => { - goto('/'); + goto(resolve('/')); }, 2000); } else { notice = { @@ -131,7 +132,7 @@ } function cancelar() { - goto('/'); + goto(resolve('/')); } @@ -161,7 +162,7 @@ diff --git a/apps/web/src/routes/(dashboard)/compras/+page.svelte b/apps/web/src/routes/(dashboard)/compras/+page.svelte index 619c5c0..e6497f9 100644 --- a/apps/web/src/routes/(dashboard)/compras/+page.svelte +++ b/apps/web/src/routes/(dashboard)/compras/+page.svelte @@ -1,11 +1,12 @@
    diff --git a/apps/web/src/routes/(dashboard)/comunicacao/+page.svelte b/apps/web/src/routes/(dashboard)/comunicacao/+page.svelte index 9caada5..2166880 100644 --- a/apps/web/src/routes/(dashboard)/comunicacao/+page.svelte +++ b/apps/web/src/routes/(dashboard)/comunicacao/+page.svelte @@ -1,11 +1,12 @@
    diff --git a/apps/web/src/routes/(dashboard)/controladoria/+page.svelte b/apps/web/src/routes/(dashboard)/controladoria/+page.svelte index 440da96..74917ac 100644 --- a/apps/web/src/routes/(dashboard)/controladoria/+page.svelte +++ b/apps/web/src/routes/(dashboard)/controladoria/+page.svelte @@ -1,12 +1,13 @@
    diff --git a/apps/web/src/routes/(dashboard)/esqueci-senha/+page.svelte b/apps/web/src/routes/(dashboard)/esqueci-senha/+page.svelte index 9d85216..989b244 100644 --- a/apps/web/src/routes/(dashboard)/esqueci-senha/+page.svelte +++ b/apps/web/src/routes/(dashboard)/esqueci-senha/+page.svelte @@ -2,6 +2,7 @@ import { useConvexClient } from 'convex-svelte'; import { api } from '@sgse-app/backend/convex/_generated/api'; + import { resolve } from '$app/paths'; const convex = useConvexClient(); let matricula = $state(''); @@ -88,7 +89,7 @@ @@ -204,7 +205,7 @@
    - +
    - + import { DollarSign, Building2, Plus, Calculator, TrendingUp, FileText } from "lucide-svelte"; + import { resolve } from "$app/paths";
    diff --git a/apps/web/src/routes/(dashboard)/gestao-pessoas/+page.svelte b/apps/web/src/routes/(dashboard)/gestao-pessoas/+page.svelte index acc3a39..74d5f63 100644 --- a/apps/web/src/routes/(dashboard)/gestao-pessoas/+page.svelte +++ b/apps/web/src/routes/(dashboard)/gestao-pessoas/+page.svelte @@ -1,4 +1,5 @@
    diff --git a/apps/web/src/routes/(dashboard)/licitacoes/+page.svelte b/apps/web/src/routes/(dashboard)/licitacoes/+page.svelte index 6075af1..65b2844 100644 --- a/apps/web/src/routes/(dashboard)/licitacoes/+page.svelte +++ b/apps/web/src/routes/(dashboard)/licitacoes/+page.svelte @@ -1,12 +1,13 @@
    diff --git a/apps/web/src/routes/(dashboard)/programas-esportivos/+page.svelte b/apps/web/src/routes/(dashboard)/programas-esportivos/+page.svelte index 47809cc..60340ef 100644 --- a/apps/web/src/routes/(dashboard)/programas-esportivos/+page.svelte +++ b/apps/web/src/routes/(dashboard)/programas-esportivos/+page.svelte @@ -1,11 +1,12 @@
    diff --git a/apps/web/src/routes/(dashboard)/recursos-humanos/atestados-licencas/+page.svelte b/apps/web/src/routes/(dashboard)/recursos-humanos/atestados-licencas/+page.svelte index a346d4b..d4be00d 100644 --- a/apps/web/src/routes/(dashboard)/recursos-humanos/atestados-licencas/+page.svelte +++ b/apps/web/src/routes/(dashboard)/recursos-humanos/atestados-licencas/+page.svelte @@ -1,5 +1,6 @@ diff --git a/apps/web/src/routes/(dashboard)/ti/auditoria/+page.svelte b/apps/web/src/routes/(dashboard)/ti/auditoria/+page.svelte index 85ccaa2..85e4d2e 100644 --- a/apps/web/src/routes/(dashboard)/ti/auditoria/+page.svelte +++ b/apps/web/src/routes/(dashboard)/ti/auditoria/+page.svelte @@ -2,9 +2,11 @@ import { useQuery } from "convex-svelte"; import { api } from "@sgse-app/backend/convex/_generated/api"; + + import { resolve } from "$app/paths"; let abaAtiva = $state<"atividades" | "logins">("atividades"); let limite = $state(50); - + // Queries com $derived para garantir reatividade const atividades = $derived(useQuery(api.logsAtividades.listarAtividades, { limite })); const logins = $derived(useQuery(api.logsLogin.listarTodosLogins, { limite })); @@ -55,7 +57,7 @@ @@ -124,7 +126,7 @@
    - -
    - +
    - + {#if !atividades?.data}
    @@ -279,7 +281,7 @@
    {logins.data.length} registro{logins.data.length !== 1 ? 's' : ''}
    {/if}
    - + {#if !logins?.data}
    diff --git a/apps/web/src/routes/(dashboard)/ti/painel-administrativo/+page.svelte b/apps/web/src/routes/(dashboard)/ti/painel-administrativo/+page.svelte index d005651..c8a798b 100644 --- a/apps/web/src/routes/(dashboard)/ti/painel-administrativo/+page.svelte +++ b/apps/web/src/routes/(dashboard)/ti/painel-administrativo/+page.svelte @@ -4,20 +4,21 @@ import StatsCard from "$lib/components/ti/StatsCard.svelte"; import { BarChart3, Users, CheckCircle2, Ban, Clock, Plus, Layers, FileText, Info } from "lucide-svelte"; + import { resolve } from "$app/paths"; const client = useConvexClient(); const usuariosQuery = useQuery(api.usuarios.listar, {}); - + // Verificar se está carregando const carregando = $derived(usuariosQuery === undefined); - + // Extrair dados dos usuários const usuarios = $derived(usuariosQuery?.data ?? []); - + // Estatísticas derivadas const stats = $derived.by(() => { // Se ainda está carregando, retorna null para mostrar loading if (carregando) return null; - + // Se não há usuários, retorna stats zeradas (mas não null para não mostrar loading) if (!Array.isArray(usuarios) || usuarios.length === 0) { return { @@ -27,11 +28,11 @@ inativos: 0 }; } - + const ativos = usuarios.filter(u => u.ativo && !u.bloqueado).length; const bloqueados = usuarios.filter(u => u.bloqueado === true).length; const inativos = usuarios.filter(u => !u.ativo).length; - + return { total: usuarios.length, ativos, @@ -58,32 +59,32 @@ {#if stats}
    - - - - - - -

    Ações Rápidas

    - + Criar Usuário - - + + Gerenciar Perfis - - + + Ver Logs diff --git a/apps/web/src/routes/(dashboard)/ti/perfis/+page.svelte b/apps/web/src/routes/(dashboard)/ti/perfis/+page.svelte index 7d3ab7d..c3017c3 100644 --- a/apps/web/src/routes/(dashboard)/ti/perfis/+page.svelte +++ b/apps/web/src/routes/(dashboard)/ti/perfis/+page.svelte @@ -1,4 +1,5 @@ @@ -8,7 +9,7 @@ -
    diff --git a/apps/web/src/routes/(dashboard)/ti/usuarios/+page.svelte b/apps/web/src/routes/(dashboard)/ti/usuarios/+page.svelte index f93c768..f2dc39f 100644 --- a/apps/web/src/routes/(dashboard)/ti/usuarios/+page.svelte +++ b/apps/web/src/routes/(dashboard)/ti/usuarios/+page.svelte @@ -1,4 +1,5 @@ + +
    +
    +
    +
    +

    + {solicitacao.funcionario?.nome || 'Funcionário'} +

    +

    + Ano de Referência: {solicitacao.anoReferencia} +

    +
    +
    + {getStatusTexto(solicitacao.status)} +
    +
    + + +
    +

    Períodos Solicitados

    +
    + {#each solicitacao.periodos as periodo, index (index)} +
    +
    {index + 1}
    +
    +
    + Início: + {new Date(periodo.dataInicio).toLocaleDateString('pt-BR')} +
    +
    + Fim: + {new Date(periodo.dataFim).toLocaleDateString('pt-BR')} +
    +
    + Dias: + {periodo.diasCorridos} +
    +
    +
    + {/each} +
    +
    + + + {#if solicitacao.observacao} +
    +

    Observações

    +
    + {solicitacao.observacao} +
    +
    + {/if} + + + {#if solicitacao.historicoAlteracoes && solicitacao.historicoAlteracoes.length > 0} +
    +

    Histórico

    +
    + {#each solicitacao.historicoAlteracoes as hist (hist.data)} +
    + + + + {formatarData(hist.data)} + - + {hist.acao} +
    + {/each} +
    +
    + {/if} + + + {#if solicitacao.status !== 'aguardando_aprovacao'} +
    +
    + + + +
    +

    Alterar Status

    +
    + Ao voltar para "Aguardando Aprovação", a solicitação ficará disponível para aprovação ou + reprovação pelo gestor. +
    +
    +
    + +
    + +
    + {:else} +
    +
    + + + + Esta solicitação já está aguardando aprovação. +
    + {/if} + + + {#if solicitacao.status === 'reprovado' && solicitacao.motivoReprovacao} +
    + + + +
    +
    Motivo da Reprovação:
    +
    {solicitacao.motivoReprovacao}
    +
    +
    + {/if} + + + {#if erro} +
    + + + + {erro} +
    + {/if} + + + {#if onCancelar} +
    + +
    + {/if} +
    +
    diff --git a/apps/web/src/lib/components/ti/charts/BarChart3D.svelte b/apps/web/src/lib/components/ti/charts/BarChart3D.svelte new file mode 100644 index 0000000..cef1b58 --- /dev/null +++ b/apps/web/src/lib/components/ti/charts/BarChart3D.svelte @@ -0,0 +1,372 @@ + + +
    + +
    diff --git a/apps/web/src/routes/(dashboard)/perfil/+page.svelte b/apps/web/src/routes/(dashboard)/perfil/+page.svelte index 3da2728..dc835ef 100644 --- a/apps/web/src/routes/(dashboard)/perfil/+page.svelte +++ b/apps/web/src/routes/(dashboard)/perfil/+page.svelte @@ -91,6 +91,7 @@ : { data: null } ); + // Query para times onde o usuário é gestor - usando $derived para garantir reatividade const meusTimesGestorQuery = $derived( currentUser?.data?._id ? useQuery(api.times.listarPorGestor, { @@ -105,6 +106,8 @@ const minhasSolicitacoes = $derived(minhasSolicitacoesQuery?.data || []); const minhasAusencias = $derived(minhasAusenciasQuery?.data || []); const meuTime = $derived(meuTimeQuery?.data); + + // Extração de meusTimesGestor const meusTimesGestor = $derived(meusTimesGestorQuery?.data || []); // Verificar se é gestor diff --git a/apps/web/src/routes/(dashboard)/recursos-humanos/atestados-licencas/+page.svelte b/apps/web/src/routes/(dashboard)/recursos-humanos/atestados-licencas/+page.svelte index a346d4b..028d93f 100644 --- a/apps/web/src/routes/(dashboard)/recursos-humanos/atestados-licencas/+page.svelte +++ b/apps/web/src/routes/(dashboard)/recursos-humanos/atestados-licencas/+page.svelte @@ -776,9 +776,243 @@ {#if eventosQuery?.data} - +
    + +
    {/if} + + {#if graficosQuery?.data} +
    +
    +

    Funcionários Atualmente Afastados

    + {#if graficosQuery.data.funcionariosAfastados.length > 0} +
    + + + + + + + + + + + {#each graficosQuery.data.funcionariosAfastados as item} + + + + + + + {/each} + +
    FuncionárioTipoData InícioData Fim
    {item.funcionarioNome} + + {item.tipo === 'atestado_medico' + ? 'Atestado Médico' + : item.tipo === 'declaracao_comparecimento' + ? 'Declaração' + : item.tipo === 'maternidade' + ? 'Licença Maternidade' + : item.tipo === 'paternidade' + ? 'Licença Paternidade' + : item.tipo} + + {formatarData(item.dataInicio)}{formatarData(item.dataFim)}
    +
    + {:else} +
    + Nenhum funcionário afastado no momento +
    + {/if} +
    +
    + {/if} + + +
    +
    +

    Registros

    +
    + + + + + + + + + + + + + + {#each registrosFiltrados.atestados as atestado} + + + + + + + + + + {/each} + {#each registrosFiltrados.licencas as licenca} + + + + + + + + + + {/each} + +
    FuncionárioTipoData InícioData FimDiasStatusAções
    {atestado.funcionario?.nome || '-'} + + {atestado.tipo === 'atestado_medico' ? 'Atestado Médico' : 'Declaração'} + + {formatarData(atestado.dataInicio)}{formatarData(atestado.dataFim)}{atestado.dias} + + {atestado.status === 'ativo' ? 'Ativo' : 'Finalizado'} + + +
    + {#if atestado.documentoId} + + {/if} + +
    +
    {licenca.funcionario?.nome || '-'} + + Licença{' '} + {licenca.tipo === 'maternidade' ? 'Maternidade' : 'Paternidade'} + {licenca.ehProrrogacao ? ' (Prorrogação)' : ''} + + {formatarData(licenca.dataInicio)}{formatarData(licenca.dataFim)}{licenca.dias} + + {licenca.status === 'ativo' ? 'Ativo' : 'Finalizado'} + + +
    + {#if licenca.documentoId} + + {/if} + +
    +
    + {#if registrosFiltrados.atestados.length === 0 && registrosFiltrados.licencas.length === 0} +
    Nenhum registro encontrado
    + {/if} +
    +
    +
    + {#if graficosQuery?.data} {@const dados = graficosQuery.data.totalDiasPorTipo} @@ -1060,237 +1294,7 @@
    - - -
    -
    -

    Funcionários Atualmente Afastados

    - {#if graficosQuery.data.funcionariosAfastados.length > 0} -
    - - - - - - - - - - - {#each graficosQuery.data.funcionariosAfastados as item} - - - - - - - {/each} - -
    FuncionárioTipoData InícioData Fim
    {item.funcionarioNome} - - {item.tipo === 'atestado_medico' - ? 'Atestado Médico' - : item.tipo === 'declaracao_comparecimento' - ? 'Declaração' - : item.tipo === 'maternidade' - ? 'Licença Maternidade' - : item.tipo === 'paternidade' - ? 'Licença Paternidade' - : item.tipo} - - {formatarData(item.dataInicio)}{formatarData(item.dataFim)}
    -
    - {:else} -
    - Nenhum funcionário afastado no momento -
    - {/if} -
    -
    {/if} - - -
    -
    -

    Registros

    -
    - - - - - - - - - - - - - - {#each registrosFiltrados.atestados as atestado} - - - - - - - - - - {/each} - {#each registrosFiltrados.licencas as licenca} - - - - - - - - - - {/each} - -
    FuncionárioTipoData InícioData FimDiasStatusAções
    {atestado.funcionario?.nome || '-'} - - {atestado.tipo === 'atestado_medico' ? 'Atestado Médico' : 'Declaração'} - - {formatarData(atestado.dataInicio)}{formatarData(atestado.dataFim)}{atestado.dias} - - {atestado.status === 'ativo' ? 'Ativo' : 'Finalizado'} - - -
    - {#if atestado.documentoId} - - {/if} - -
    -
    {licenca.funcionario?.nome || '-'} - - Licença{' '} - {licenca.tipo === 'maternidade' ? 'Maternidade' : 'Paternidade'} - {licenca.ehProrrogacao ? ' (Prorrogação)' : ''} - - {formatarData(licenca.dataInicio)}{formatarData(licenca.dataFim)}{licenca.dias} - - {licenca.status === 'ativo' ? 'Ativo' : 'Finalizado'} - - -
    - {#if licenca.documentoId} - - {/if} - -
    -
    - {#if registrosFiltrados.atestados.length === 0 && registrosFiltrados.licencas.length === 0} -
    Nenhum registro encontrado
    - {/if} -
    -
    -
    {:else if abaAtiva === 'atestado'}
    diff --git a/apps/web/src/routes/(dashboard)/recursos-humanos/ferias/+page.svelte b/apps/web/src/routes/(dashboard)/recursos-humanos/ferias/+page.svelte index cd6d2f2..2ac2bf0 100644 --- a/apps/web/src/routes/(dashboard)/recursos-humanos/ferias/+page.svelte +++ b/apps/web/src/routes/(dashboard)/recursos-humanos/ferias/+page.svelte @@ -1,12 +1,14 @@ @@ -1316,6 +1503,51 @@
    {/if} + + {#if isLoading && !hasError} +
    +
    +
    +
    +
    +
    + {:else if !hasError} +
    +
    +
    +
    + + + +
    +
    +

    Calendário Geral de Férias

    +

    + Visualize os períodos aprovados diretamente no calendário interativo +

    +
    +
    +
    +
    +
    +
    +
    + {/if} + {#if !isLoading || !hasError}
    @@ -1450,6 +1682,7 @@ Total Dias Status Solicitado em + Ações @@ -1495,6 +1728,35 @@
    {formatarData(solicitacao._creationTime)} + + + {/each} @@ -1549,168 +1811,60 @@
    - - {#if periodosPorMesAtivos.length === 0} - Sem dados registrados até o momento. - {:else} - {@const maxDias = Math.max( - 1, - getMax(periodosPorMesAtivos, (p) => p.totalDias) - )} - {#each [0, 1, 2, 3, 4, 5] as passo (passo)} - {@const valor = Math.round((maxDias / 5) * passo)} - {@const y = chartHeight - padding.bottom - scaleY(valor, maxDias)} - - - {valor} dia(s) - - {/each} - - - p.totalDias, maxDias)} - fill="url(#gradient-ferias-mes)" - opacity="0.75" - /> - { - const x = getX(index, periodosPorMesAtivos.length); - const y = chartHeight - padding.bottom - scaleY(item.totalDias, maxDias); - return `${x},${y}`; - }) - .join(' ')} - fill="none" - stroke="rgb(59, 130, 246)" - stroke-width="3" - stroke-linecap="round" - /> - {#each periodosPorMesAtivos as item, index (item.label)} - {@const x = getX(index, periodosPorMesAtivos.length)} - {@const y = chartHeight - padding.bottom - scaleY(item.totalDias, maxDias)} - - - {item.totalDias} dia(s) - - - {item.quantidadePeriodos} período(s) - - {/each} - {#each periodosPorMesAtivos as item, index (item.label)} - {@const x = getX(index, periodosPorMesAtivos.length)} - -
    - {item.label} -
    -
    - {/each} - - - - - - - {/if} -
    - {#if periodosPorMes.length > 1} -
    -
    - Janela exibida - - {periodosPorMes[rangeInicioIndice]?.label ?? '-'} - → - {periodosPorMes[rangeFimIndice]?.label ?? '-'} - -
    -
    -
    - - -
    -
    - - -
    -
    -

    - Ajuste com o mouse os intervalos exibidos no gráfico. -

    + {#if periodosPorMesAtivos.length === 0} +
    +

    Sem dados registrados até o momento.

    + {:else} + + {#if periodosPorMes.length > 1} +
    +
    + Janela exibida + + {periodosPorMes[rangeInicioIndice]?.label ?? '-'} + → + {periodosPorMes[rangeFimIndice]?.label ?? '-'} + +
    +
    +
    + + +
    +
    + + +
    +
    +

    + Ajuste com o mouse os intervalos exibidos no gráfico. +

    +
    + {/if} {/if}
    @@ -1746,166 +1900,49 @@
  • - - {#if solicitacoesPorAno.length === 0} - Ainda não há solicitações registradas para exibição. - {:else} - {@const maxDiasAno = Math.max( - 1, - getMax(solicitacoesPorAno, (item) => item.diasTotais) - )} - {#each [0, 1, 2, 3, 4, 5] as passo (passo)} - {@const valor = Math.round((maxDiasAno / 5) * passo)} - {@const y = chartHeight - padding.bottom - scaleY(valor, maxDiasAno)} - - - {valor} dia(s) - - {/each} - - - item.diasTotais, maxDiasAno)} - fill="url(#gradient-ferias-ano)" - opacity="0.75" - /> - { - const x = getX(index, solicitacoesPorAno.length); - const y = chartHeight - padding.bottom - scaleY(item.diasTotais, maxDiasAno); - return `${x},${y}`; - }) - .join(' ')} - fill="none" - stroke="rgb(16, 185, 129)" - stroke-width="3" - stroke-linecap="round" - /> - {#each solicitacoesPorAno as item, index (item.ano)} - {@const x = getX(index, solicitacoesPorAno.length)} - {@const y = chartHeight - padding.bottom - scaleY(item.diasTotais, maxDiasAno)} - - - {item.diasTotais} dia(s) - - - {item.solicitacoes} solicitação(ões) - - {/each} - {#each solicitacoesPorAno as item, index (item.ano)} - {@const x = getX(index, solicitacoesPorAno.length)} - -
    - {item.ano} -
    -
    - {/each} - - - - - - - {/if} -
    -
    - - - - -
    -
    -
    -
    - - - -
    -
    -

    Calendário Geral de Férias

    -

    - Visualize os períodos aprovados diretamente no calendário interativo -

    -
    -
    -
    -
    + {#if solicitacoesPorAno.length === 0} +
    +

    + Ainda não há solicitações registradas para exibição. +

    +
    + {:else} + + {/if}
    {/if} + + +{#if solicitacaoSelecionada && currentUser.data} + {#await client.query( api.ferias.obterDetalhes, { solicitacaoId: solicitacaoSelecionada } ) then detalhes} + {#if detalhes} + + + + + {/if} + {/await} +{/if} +